mirror of
https://github.com/justinian/jsix.git
synced 2025-12-10 00:14:32 -08:00
[boot] Restructure boot paging and program loading
Restructuring paging into an object that carries its page cache with it and makes for simpler code. Program loading is also changed to not copy the pages loaded from the file into new pages - we can impose a new constraint that anything loaded by boot have a simple, page-aligned layout so that we can just map the existing pages into the right addresses. Also included are some linker script changes to help accommodate this.
This commit is contained in:
@@ -1,7 +1,6 @@
|
|||||||
#include <uefi/boot_services.h>
|
#include <uefi/boot_services.h>
|
||||||
#include <uefi/types.h>
|
#include <uefi/types.h>
|
||||||
|
|
||||||
#include <bootproto/init.h>
|
|
||||||
#include <elf/file.h>
|
#include <elf/file.h>
|
||||||
#include <elf/headers.h>
|
#include <elf/headers.h>
|
||||||
#include <util/pointers.h>
|
#include <util/pointers.h>
|
||||||
@@ -22,9 +21,7 @@ namespace loader {
|
|||||||
using memory::alloc_type;
|
using memory::alloc_type;
|
||||||
|
|
||||||
util::buffer
|
util::buffer
|
||||||
load_file(
|
load_file(fs::file &disk, const wchar_t *path)
|
||||||
fs::file &disk,
|
|
||||||
const wchar_t *path)
|
|
||||||
{
|
{
|
||||||
status_line status(L"Loading file", path);
|
status_line status(L"Loading file", path);
|
||||||
|
|
||||||
@@ -61,20 +58,10 @@ verify_kernel_header(elf::file &kernel, util::const_buffer data)
|
|||||||
header->version_gitsha);
|
header->version_gitsha);
|
||||||
}
|
}
|
||||||
|
|
||||||
bootproto::program *
|
inline void
|
||||||
load_program(
|
elf_error(const elf::file &elf, util::const_buffer data)
|
||||||
fs::file &disk,
|
|
||||||
const wchar_t *name,
|
|
||||||
const descriptor &desc,
|
|
||||||
bool verify)
|
|
||||||
{
|
{
|
||||||
status_line status(L"Loading program", name);
|
auto *header = elf.header();
|
||||||
|
|
||||||
util::const_buffer data = load_file(disk, desc.path);
|
|
||||||
|
|
||||||
elf::file program {data};
|
|
||||||
if (!program.valid()) {
|
|
||||||
auto *header = program.header();
|
|
||||||
console::print(L" progam size: %d\r\n", data.count);
|
console::print(L" progam size: %d\r\n", data.count);
|
||||||
console::print(L" word size: %d\r\n", header->word_size);
|
console::print(L" word size: %d\r\n", header->word_size);
|
||||||
console::print(L" endianness: %d\r\n", header->endianness);
|
console::print(L" endianness: %d\r\n", header->endianness);
|
||||||
@@ -85,49 +72,94 @@ load_program(
|
|||||||
console::print(L" ELF version: %d\r\n", header->version);
|
console::print(L" ELF version: %d\r\n", header->version);
|
||||||
|
|
||||||
error::raise(uefi::status::load_error, L"ELF file not valid");
|
error::raise(uefi::status::load_error, L"ELF file not valid");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (verify)
|
inline uintptr_t
|
||||||
verify_kernel_header(program, data);
|
allocate_bss(elf::segment_header seg)
|
||||||
|
{
|
||||||
|
size_t page_count = memory::bytes_to_pages(seg.mem_size);
|
||||||
|
void *pages = g_alloc.allocate_pages(page_count, alloc_type::program, true);
|
||||||
|
return reinterpret_cast<uintptr_t>(pages);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
parse_program(const wchar_t *name, util::const_buffer data, bootproto::program &program)
|
||||||
|
{
|
||||||
|
status_line status(L"Preparing program", name);
|
||||||
|
|
||||||
|
elf::file elf {data};
|
||||||
|
if (!elf.valid())
|
||||||
|
elf_error(elf, data); // does not return
|
||||||
|
|
||||||
size_t num_sections = 0;
|
size_t num_sections = 0;
|
||||||
for (auto &seg : program.segments()) {
|
for (auto &seg : elf.segments()) {
|
||||||
if (seg.type == elf::segment_type::load)
|
if (seg.type == elf::segment_type::load)
|
||||||
++num_sections;
|
++num_sections;
|
||||||
}
|
}
|
||||||
|
|
||||||
bootproto::program_section *sections = new bootproto::program_section [num_sections];
|
bootproto::program_section *sections =
|
||||||
|
new bootproto::program_section [num_sections];
|
||||||
|
|
||||||
size_t next_section = 0;
|
size_t next_section = 0;
|
||||||
for (auto &seg : program.segments()) {
|
for (auto &seg : elf.segments()) {
|
||||||
if (seg.type != elf::segment_type::load)
|
if (seg.type != elf::segment_type::load)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
bootproto::program_section §ion = sections[next_section++];
|
bootproto::program_section §ion = sections[next_section++];
|
||||||
|
section.phys_addr = elf.base() + seg.offset;
|
||||||
uintptr_t virt_addr = seg.vaddr;
|
section.virt_addr = seg.vaddr;
|
||||||
size_t mem_size = seg.mem_size;
|
section.size = seg.mem_size;
|
||||||
|
|
||||||
// Page-align the section, which may require increasing the size
|
|
||||||
size_t prelude = virt_addr & 0xfff;
|
|
||||||
mem_size += prelude;
|
|
||||||
virt_addr &= ~0xfffull;
|
|
||||||
|
|
||||||
size_t page_count = memory::bytes_to_pages(mem_size);
|
|
||||||
void *pages = g_alloc.allocate_pages(page_count, alloc_type::program, true);
|
|
||||||
const void *source = util::offset_pointer(data.pointer, seg.offset);
|
|
||||||
g_alloc.copy(util::offset_pointer(pages, prelude), source, seg.file_size);
|
|
||||||
section.phys_addr = reinterpret_cast<uintptr_t>(pages);
|
|
||||||
section.virt_addr = virt_addr;
|
|
||||||
section.size = mem_size;
|
|
||||||
section.type = static_cast<bootproto::section_flags>(seg.flags);
|
section.type = static_cast<bootproto::section_flags>(seg.flags);
|
||||||
|
|
||||||
|
if (seg.mem_size != seg.file_size)
|
||||||
|
section.phys_addr = allocate_bss(seg);
|
||||||
}
|
}
|
||||||
|
|
||||||
bootproto::program *prog = new bootproto::program;
|
program.sections = { .pointer = sections, .count = num_sections };
|
||||||
prog->sections = { .pointer = sections, .count = num_sections };
|
program.phys_base = elf.base();
|
||||||
prog->phys_base = program.base();
|
program.entrypoint = elf.entrypoint();
|
||||||
prog->entrypoint = program.entrypoint();
|
}
|
||||||
return prog;
|
|
||||||
|
uintptr_t
|
||||||
|
load_program(
|
||||||
|
util::const_buffer data,
|
||||||
|
const wchar_t *name,
|
||||||
|
paging::pager &pager,
|
||||||
|
bool verify)
|
||||||
|
{
|
||||||
|
using util::bits::has;
|
||||||
|
|
||||||
|
status_line status(L"Loading program", name);
|
||||||
|
|
||||||
|
elf::file elf {data};
|
||||||
|
if (!elf.valid())
|
||||||
|
elf_error(elf, data); // does not return
|
||||||
|
|
||||||
|
if (verify)
|
||||||
|
verify_kernel_header(elf, data);
|
||||||
|
|
||||||
|
size_t num_sections = 0;
|
||||||
|
for (auto &seg : elf.segments()) {
|
||||||
|
if (seg.type == elf::segment_type::load)
|
||||||
|
++num_sections;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto &seg : elf.segments()) {
|
||||||
|
if (seg.type != elf::segment_type::load)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
uintptr_t phys_addr = elf.base() + seg.offset;
|
||||||
|
if (seg.mem_size != seg.file_size)
|
||||||
|
phys_addr = allocate_bss(seg);
|
||||||
|
|
||||||
|
pager.map_pages(phys_addr, seg.vaddr,
|
||||||
|
memory::bytes_to_pages(seg.mem_size),
|
||||||
|
has(seg.flags, elf::segment_flags::write),
|
||||||
|
has(seg.flags, elf::segment_flags::exec));
|
||||||
|
}
|
||||||
|
|
||||||
|
return elf.entrypoint();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <bootproto/init.h>
|
#include <bootproto/init.h>
|
||||||
|
#include <bootproto/kernel.h>
|
||||||
#include <util/counted.h>
|
#include <util/counted.h>
|
||||||
|
|
||||||
namespace bootproto {
|
namespace bootproto {
|
||||||
@@ -11,32 +12,47 @@ namespace bootproto {
|
|||||||
|
|
||||||
namespace boot {
|
namespace boot {
|
||||||
|
|
||||||
class descriptor;
|
namespace fs { class file; }
|
||||||
|
namespace paging { class pager; }
|
||||||
namespace fs {
|
|
||||||
class file;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace loader {
|
namespace loader {
|
||||||
|
|
||||||
|
// Bootloader ELF file requirements
|
||||||
|
// ================================
|
||||||
|
// The bootloader accepts a subset of valid ELF files to load, with
|
||||||
|
// the following requiresments:
|
||||||
|
// 1. All program segments are page-aligned.
|
||||||
|
// 2. PT_LOAD segments cannot contain a mix of PROGBITS and NOBITS
|
||||||
|
// sections. i.e., section memory size must equal either zero or
|
||||||
|
// its file size.
|
||||||
|
// 3. There are only one or zero PT_LOAD NOBITS program segments.
|
||||||
|
|
||||||
|
|
||||||
/// Load a file from disk into memory.
|
/// Load a file from disk into memory.
|
||||||
/// \arg disk The opened UEFI filesystem to load from
|
/// \arg disk The opened UEFI filesystem to load from
|
||||||
/// \arg path The path of the file to load
|
/// \arg path The path of the file to load
|
||||||
util::buffer
|
util::buffer load_file(fs::file &disk, const wchar_t *path);
|
||||||
load_file(
|
|
||||||
fs::file &disk,
|
|
||||||
const wchar_t *path);
|
|
||||||
|
|
||||||
/// Parse and load an ELF file in memory into a loaded image.
|
/// Parse a buffer holding ELF data into a bootproto::program
|
||||||
/// \arg disk The opened UEFI filesystem to load from
|
|
||||||
/// \arg desc The descriptor identifying the program
|
|
||||||
/// \arg name The human-readable name of the program to load
|
/// \arg name The human-readable name of the program to load
|
||||||
/// \arg verify If this is the kernel and should have its header verified
|
/// \arg data A buffer containing an ELF executable
|
||||||
bootproto::program *
|
/// \arg program A program structure to fill
|
||||||
load_program(
|
void parse_program(
|
||||||
fs::file &disk,
|
|
||||||
const wchar_t *name,
|
const wchar_t *name,
|
||||||
const descriptor &desc,
|
util::const_buffer data,
|
||||||
|
bootproto::program &program);
|
||||||
|
|
||||||
|
/// Parse a buffer holding ELF data and map it to be runnable
|
||||||
|
/// \arg data The ELF data in memory
|
||||||
|
/// \arg name The human-readable name of the program to load
|
||||||
|
/// \arg pager The kernel space pager, to map programs into
|
||||||
|
/// \arg verify If this is the kernel and should have its header verified
|
||||||
|
/// \returns The entrypoint to the loaded program
|
||||||
|
uintptr_t
|
||||||
|
load_program(
|
||||||
|
util::const_buffer data,
|
||||||
|
const wchar_t *name,
|
||||||
|
paging::pager &pager,
|
||||||
bool verify = false);
|
bool verify = false);
|
||||||
|
|
||||||
/// Load a file from disk into memory, creating an init args module
|
/// Load a file from disk into memory, creating an init args module
|
||||||
|
|||||||
@@ -60,14 +60,17 @@ uefi_preboot(uefi::handle image, uefi::system_table *st)
|
|||||||
args->acpi_table = hw::find_acpi_table(st);
|
args->acpi_table = hw::find_acpi_table(st);
|
||||||
memory::mark_pointer_fixup(&args->runtime_services);
|
memory::mark_pointer_fixup(&args->runtime_services);
|
||||||
|
|
||||||
paging::allocate_tables(args);
|
|
||||||
|
|
||||||
return args;
|
return args;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Load the kernel and other programs from disk
|
/// Load the kernel and other programs from disk
|
||||||
void
|
bootproto::entrypoint
|
||||||
load_resources(bootproto::args *args, video::screen *screen, uefi::handle image, uefi::boot_services *bs)
|
load_resources(
|
||||||
|
bootproto::args *args,
|
||||||
|
video::screen *screen,
|
||||||
|
uefi::handle image,
|
||||||
|
paging::pager &pager,
|
||||||
|
uefi::boot_services *bs)
|
||||||
{
|
{
|
||||||
status_line status {L"Loading programs"};
|
status_line status {L"Loading programs"};
|
||||||
|
|
||||||
@@ -75,17 +78,16 @@ load_resources(bootproto::args *args, video::screen *screen, uefi::handle image,
|
|||||||
util::buffer bc_data = loader::load_file(disk, L"jsix\\boot.conf");
|
util::buffer bc_data = loader::load_file(disk, L"jsix\\boot.conf");
|
||||||
bootconfig bc {bc_data, bs};
|
bootconfig bc {bc_data, bs};
|
||||||
|
|
||||||
args->kernel = loader::load_program(disk, L"kernel", bc.kernel(), true);
|
util::buffer kernel = loader::load_file(disk, bc.kernel().path);
|
||||||
args->init = loader::load_program(disk, L"init server", bc.init());
|
uintptr_t kentry = loader::load_program(kernel, L"jsix kernel", pager, true);
|
||||||
args->flags = static_cast<bootproto::boot_flags>(bc.flags());
|
|
||||||
|
|
||||||
loader::load_module(disk, L"initrd", bc.initrd(),
|
args->flags = static_cast<bootproto::boot_flags>(bc.flags());
|
||||||
bootproto::module_type::initrd, 0);
|
|
||||||
|
|
||||||
namespace bits = util::bits;
|
namespace bits = util::bits;
|
||||||
using bootproto::desc_flags;
|
using bootproto::desc_flags;
|
||||||
|
|
||||||
bool has_panic = false;
|
bool has_panic = false;
|
||||||
|
util::buffer panic;
|
||||||
|
|
||||||
if (screen) {
|
if (screen) {
|
||||||
video::make_module(screen);
|
video::make_module(screen);
|
||||||
@@ -94,7 +96,7 @@ load_resources(bootproto::args *args, video::screen *screen, uefi::handle image,
|
|||||||
// give it priority
|
// give it priority
|
||||||
for (const descriptor &d : bc.panics()) {
|
for (const descriptor &d : bc.panics()) {
|
||||||
if (bits::has(d.flags, desc_flags::graphical)) {
|
if (bits::has(d.flags, desc_flags::graphical)) {
|
||||||
args->panic = loader::load_program(disk, L"panic handler", d);
|
panic = loader::load_file(disk, d.path);
|
||||||
has_panic = true;
|
has_panic = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -104,16 +106,28 @@ load_resources(bootproto::args *args, video::screen *screen, uefi::handle image,
|
|||||||
if (!has_panic) {
|
if (!has_panic) {
|
||||||
for (const descriptor &d : bc.panics()) {
|
for (const descriptor &d : bc.panics()) {
|
||||||
if (!bits::has(d.flags, desc_flags::graphical)) {
|
if (!bits::has(d.flags, desc_flags::graphical)) {
|
||||||
args->panic = loader::load_program(disk, L"panic handler", d);
|
panic = loader::load_file(disk, d.path);
|
||||||
has_panic = true;
|
has_panic = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (has_panic) {
|
||||||
|
args->panic_handler = loader::load_program(panic, L"panic handler", pager);
|
||||||
|
|
||||||
const wchar_t *symbol_file = bc.symbols();
|
const wchar_t *symbol_file = bc.symbols();
|
||||||
if (has_panic && symbol_file && *symbol_file)
|
if (symbol_file && *symbol_file)
|
||||||
args->symbol_table = loader::load_file(disk, symbol_file).pointer;
|
args->symbol_table = loader::load_file(disk, symbol_file);
|
||||||
|
}
|
||||||
|
|
||||||
|
util::buffer init = loader::load_file(disk, bc.init().path);
|
||||||
|
loader::parse_program(L"init server", init, args->init);
|
||||||
|
|
||||||
|
loader::load_module(disk, L"initrd", bc.initrd(),
|
||||||
|
bootproto::module_type::initrd, 0);
|
||||||
|
|
||||||
|
return reinterpret_cast<bootproto::entrypoint>(kentry);
|
||||||
}
|
}
|
||||||
|
|
||||||
memory::efi_mem_map
|
memory::efi_mem_map
|
||||||
@@ -156,35 +170,31 @@ efi_main(uefi::handle image, uefi::system_table *st)
|
|||||||
con.announce();
|
con.announce();
|
||||||
|
|
||||||
bootproto::args *args = uefi_preboot(image, st);
|
bootproto::args *args = uefi_preboot(image, st);
|
||||||
load_resources(args, screen, image, bs);
|
|
||||||
|
paging::pager pager {bs};
|
||||||
|
|
||||||
|
bootproto::entrypoint kentry =
|
||||||
|
load_resources(args, screen, image, pager, bs);
|
||||||
|
|
||||||
|
pager.update_kernel_args(args);
|
||||||
memory::efi_mem_map map = uefi_exit(args, image, st->boot_services);
|
memory::efi_mem_map map = uefi_exit(args, image, st->boot_services);
|
||||||
|
|
||||||
args->allocations = allocs;
|
args->allocations = allocs;
|
||||||
args->modules = reinterpret_cast<uintptr_t>(modules);
|
args->init_modules = reinterpret_cast<uintptr_t>(modules);
|
||||||
|
|
||||||
status_bar status {screen}; // Switch to fb status display
|
status_bar status {screen}; // Switch to fb status display
|
||||||
|
|
||||||
// Map the kernel and panic handler to the appropriate addresses
|
memory::fix_frame_blocks(args, pager);
|
||||||
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();
|
//status.next();
|
||||||
|
|
||||||
hw::setup_control_regs();
|
hw::setup_control_regs();
|
||||||
memory::virtualize(args->pml4, map, st->runtime_services);
|
memory::virtualize(pager, map, st->runtime_services);
|
||||||
//status.next();
|
//status.next();
|
||||||
|
|
||||||
change_pointer(args);
|
change_pointer(args);
|
||||||
change_pointer(args->pml4);
|
change_pointer(args->pml4);
|
||||||
|
change_pointer(args->init.sections.pointer);
|
||||||
change_pointer(args->kernel);
|
|
||||||
change_pointer(args->kernel->sections.pointer);
|
|
||||||
change_pointer(args->init);
|
|
||||||
change_pointer(args->init->sections.pointer);
|
|
||||||
|
|
||||||
//status.next();
|
//status.next();
|
||||||
|
|
||||||
|
|||||||
@@ -57,16 +57,14 @@ mark_pointer_fixup(void **p)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
virtualize(void *pml4, efi_mem_map &map, uefi::runtime_services *rs)
|
virtualize(paging::pager &pager, efi_mem_map &map, uefi::runtime_services *rs)
|
||||||
{
|
{
|
||||||
paging::add_current_mappings(reinterpret_cast<paging::page_table*>(pml4));
|
pager.add_current_mappings();
|
||||||
|
|
||||||
for (auto &desc : map)
|
for (auto &desc : map)
|
||||||
desc.virtual_start = desc.physical_start + bootproto::mem::linear_offset;
|
desc.virtual_start = desc.physical_start + bootproto::mem::linear_offset;
|
||||||
|
|
||||||
// Write our new PML4 pointer to CR3
|
pager.install();
|
||||||
asm volatile ( "mov %0, %%cr3" :: "r" (pml4) );
|
|
||||||
__sync_synchronize();
|
|
||||||
|
|
||||||
try_or_raise(
|
try_or_raise(
|
||||||
rs->set_virtual_address_map(
|
rs->set_virtual_address_map(
|
||||||
|
|||||||
@@ -10,6 +10,11 @@ namespace uefi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
namespace boot {
|
namespace boot {
|
||||||
|
|
||||||
|
namespace paging {
|
||||||
|
class pager;
|
||||||
|
}
|
||||||
|
|
||||||
namespace memory {
|
namespace memory {
|
||||||
|
|
||||||
class efi_mem_map;
|
class efi_mem_map;
|
||||||
@@ -42,7 +47,7 @@ void mark_pointer_fixup(void **p);
|
|||||||
/// \arg pml4 The root page table for the new mappings
|
/// \arg pml4 The root page table for the new mappings
|
||||||
/// \arg map The UEFI memory map, used to update runtime services
|
/// \arg map The UEFI memory map, used to update runtime services
|
||||||
void virtualize(
|
void virtualize(
|
||||||
void *pml4,
|
paging::pager &pager,
|
||||||
efi_mem_map &map,
|
efi_mem_map &map,
|
||||||
uefi::runtime_services *rs);
|
uefi::runtime_services *rs);
|
||||||
|
|
||||||
|
|||||||
@@ -278,7 +278,7 @@ build_frame_blocks(const util::counted<bootproto::mem_entry> &kmap)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
fix_frame_blocks(bootproto::args *args)
|
fix_frame_blocks(bootproto::args *args, paging::pager &pager)
|
||||||
{
|
{
|
||||||
util::counted<frame_block> &blocks = args->frame_blocks;
|
util::counted<frame_block> &blocks = args->frame_blocks;
|
||||||
|
|
||||||
@@ -290,8 +290,7 @@ fix_frame_blocks(bootproto::args *args)
|
|||||||
uintptr_t addr = reinterpret_cast<uintptr_t>(blocks.pointer);
|
uintptr_t addr = reinterpret_cast<uintptr_t>(blocks.pointer);
|
||||||
|
|
||||||
// Map the frame blocks to the appropriate address
|
// Map the frame blocks to the appropriate address
|
||||||
paging::map_pages(args, addr,
|
pager.map_pages(addr, bootproto::mem::bitmap_offset, pages, true, false);
|
||||||
bootproto::mem::bitmap_offset, pages, true, false);
|
|
||||||
|
|
||||||
uintptr_t offset = bootproto::mem::bitmap_offset - addr;
|
uintptr_t offset = bootproto::mem::bitmap_offset - addr;
|
||||||
|
|
||||||
|
|||||||
@@ -17,6 +17,11 @@ namespace bootproto {
|
|||||||
}
|
}
|
||||||
|
|
||||||
namespace boot {
|
namespace boot {
|
||||||
|
|
||||||
|
namespace paging {
|
||||||
|
class pager;
|
||||||
|
}
|
||||||
|
|
||||||
namespace memory {
|
namespace memory {
|
||||||
|
|
||||||
/// Struct that represents UEFI's memory map. Contains a pointer to the map data
|
/// Struct that represents UEFI's memory map. Contains a pointer to the map data
|
||||||
@@ -56,7 +61,7 @@ util::counted<bootproto::mem_entry> build_kernel_map(efi_mem_map &map);
|
|||||||
util::counted<bootproto::frame_block> build_frame_blocks(const util::counted<bootproto::mem_entry> &kmap);
|
util::counted<bootproto::frame_block> build_frame_blocks(const util::counted<bootproto::mem_entry> &kmap);
|
||||||
|
|
||||||
/// Map the frame allocation maps to the right spot and fix up pointers
|
/// Map the frame allocation maps to the right spot and fix up pointers
|
||||||
void fix_frame_blocks(bootproto::args *args);
|
void fix_frame_blocks(bootproto::args *args, paging::pager &pager);
|
||||||
|
|
||||||
} // namespace boot
|
} // namespace boot
|
||||||
} // namespace memory
|
} // namespace memory
|
||||||
|
|||||||
@@ -4,7 +4,6 @@
|
|||||||
#include <util/pointers.h>
|
#include <util/pointers.h>
|
||||||
|
|
||||||
#include "allocator.h"
|
#include "allocator.h"
|
||||||
#include "console.h"
|
|
||||||
#include "error.h"
|
#include "error.h"
|
||||||
#include "loader.h"
|
#include "loader.h"
|
||||||
#include "memory.h"
|
#include "memory.h"
|
||||||
@@ -20,7 +19,7 @@ using memory::page_size;
|
|||||||
// Flags: 0 0 0 1 0 0 0 0 0 0 0 1 = 0x0101
|
// Flags: 0 0 0 1 0 0 0 0 0 0 0 1 = 0x0101
|
||||||
// IGN | | | | | | | | +- Present
|
// IGN | | | | | | | | +- Present
|
||||||
// | | | | | | | +--- Writeable
|
// | | | | | | | +--- Writeable
|
||||||
// | | | | | | +----- Usermode access (supervisor only)
|
// | | | | | | +----- Usermode access (Supervisor only)
|
||||||
// | | | | | +------- PWT (determining memory type for page)
|
// | | | | | +------- PWT (determining memory type for page)
|
||||||
// | | | | +---------- PCD (determining memory type for page)
|
// | | | | +---------- PCD (determining memory type for page)
|
||||||
// | | | +------------ Accessed flag (not accessed yet)
|
// | | | +------------ Accessed flag (not accessed yet)
|
||||||
@@ -33,7 +32,7 @@ constexpr uint64_t page_flags = 0x101;
|
|||||||
// Flags: 0 0 0 0 1 1 0 0 0 1 0 1 1 = 0x018b
|
// Flags: 0 0 0 0 1 1 0 0 0 1 0 1 1 = 0x018b
|
||||||
// | IGN | | | | | | | | +- Present
|
// | IGN | | | | | | | | +- Present
|
||||||
// | | | | | | | | +--- Writeable
|
// | | | | | | | | +--- Writeable
|
||||||
// | | | | | | | +----- Supervisor only
|
// | | | | | | | +----- Usermode access (Supervisor only)
|
||||||
// | | | | | | +------- PWT (determining memory type for page)
|
// | | | | | | +------- PWT (determining memory type for page)
|
||||||
// | | | | | +---------- PCD (determining memory type for page)
|
// | | | | | +---------- PCD (determining memory type for page)
|
||||||
// | | | | +------------ Accessed flag (not accessed yet)
|
// | | | | +------------ Accessed flag (not accessed yet)
|
||||||
@@ -57,17 +56,22 @@ constexpr uint64_t huge_page_flags = 0x18b;
|
|||||||
constexpr uint64_t table_flags = 0x003;
|
constexpr uint64_t table_flags = 0x003;
|
||||||
|
|
||||||
|
|
||||||
inline void *
|
/// Struct to allow easy accessing of a memory page being used as a page table.
|
||||||
pop_pages(util::counted<void> &pages, size_t count)
|
struct page_table
|
||||||
{
|
{
|
||||||
if (count > pages.count)
|
uint64_t entries[512];
|
||||||
error::raise(uefi::status::out_of_resources, L"Page table cache empty", 0x7ab1e5);
|
|
||||||
|
|
||||||
void *next = pages.pointer;
|
inline page_table * get(int i, uint16_t *flags = nullptr) const {
|
||||||
pages.pointer = util::offset_pointer(pages.pointer, count*page_size);
|
uint64_t entry = entries[i];
|
||||||
pages.count -= count;
|
if ((entry & 1) == 0) return nullptr;
|
||||||
return next;
|
if (flags) *flags = entry & 0xfff;
|
||||||
}
|
return reinterpret_cast<page_table *>(entry & ~0xfffull);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void set(int i, void *p, uint16_t flags) {
|
||||||
|
entries[i] = reinterpret_cast<uint64_t>(p) | (flags & 0xfff);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/// Iterator over page table entries.
|
/// Iterator over page table entries.
|
||||||
template <unsigned D = 4>
|
template <unsigned D = 4>
|
||||||
@@ -76,24 +80,22 @@ class page_entry_iterator
|
|||||||
public:
|
public:
|
||||||
/// Constructor.
|
/// Constructor.
|
||||||
/// \arg virt Virtual address this iterator is starting at
|
/// \arg virt Virtual address this iterator is starting at
|
||||||
/// \arg pml4 Root of the page tables to iterate
|
/// \arg pgr The pager, used for its page table cache
|
||||||
/// \arg pages Cache of usable table pages
|
|
||||||
page_entry_iterator(
|
page_entry_iterator(
|
||||||
uintptr_t virt,
|
uintptr_t virt,
|
||||||
page_table *pml4,
|
pager &pgr) :
|
||||||
util::counted<void> &pages) :
|
m_pager(pgr)
|
||||||
m_pages(pages)
|
|
||||||
{
|
{
|
||||||
m_table[0] = pml4;
|
m_table[0] = pgr.m_pml4;
|
||||||
for (unsigned i = 0; i < D; ++i) {
|
for (unsigned i = 0; i < D; ++i) {
|
||||||
m_index[i] = static_cast<uint16_t>((virt >> (12 + 9*(3-i))) & 0x1ff);
|
m_index[i] = static_cast<uint16_t>((virt >> (12 + 9*(3-i))) & 0x1ff);
|
||||||
ensure_table(i);
|
ensure_table(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uintptr_t vaddress() const {
|
uintptr_t vaddress(unsigned level = D) const {
|
||||||
uintptr_t address = 0;
|
uintptr_t address = 0;
|
||||||
for (unsigned i = 0; i < D; ++i)
|
for (unsigned i = 0; i < level; ++i)
|
||||||
address |= static_cast<uintptr_t>(m_index[i]) << (12 + 9*(3-i));
|
address |= static_cast<uintptr_t>(m_index[i]) << (12 + 9*(3-i));
|
||||||
if (address & (1ull<<47)) // canonicalize the address
|
if (address & (1ull<<47)) // canonicalize the address
|
||||||
address |= (0xffffull<<48);
|
address |= (0xffffull<<48);
|
||||||
@@ -114,6 +116,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
uint64_t & operator*() { return entry(D-1); }
|
uint64_t & operator*() { return entry(D-1); }
|
||||||
|
uint64_t operator[](int i) { return i < D ? m_index[i] : 0; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
inline uint64_t & entry(unsigned level) { return m_table[level]->entries[m_index[level]]; }
|
inline uint64_t & entry(unsigned level) { return m_table[level]->entries[m_index[level]]; }
|
||||||
@@ -129,7 +132,7 @@ private:
|
|||||||
uint64_t & parent_ent = entry(level - 1);
|
uint64_t & parent_ent = entry(level - 1);
|
||||||
|
|
||||||
if (!(parent_ent & 1)) {
|
if (!(parent_ent & 1)) {
|
||||||
page_table *table = reinterpret_cast<page_table*>(pop_pages(m_pages, 1));
|
page_table *table = reinterpret_cast<page_table*>(m_pager.pop_pages(1));
|
||||||
parent_ent = (reinterpret_cast<uintptr_t>(table) & ~0xfffull) | table_flags;
|
parent_ent = (reinterpret_cast<uintptr_t>(table) & ~0xfffull) | table_flags;
|
||||||
m_table[level] = table;
|
m_table[level] = table;
|
||||||
} else {
|
} else {
|
||||||
@@ -137,44 +140,62 @@ private:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
util::counted<void> &m_pages;
|
pager &m_pager;
|
||||||
page_table *m_table[D];
|
page_table *m_table[D];
|
||||||
uint16_t m_index[D];
|
uint16_t m_index[D];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pager::pager(uefi::boot_services *bs) :
|
||||||
static void
|
m_bs {bs}
|
||||||
add_offset_mappings(page_table *pml4, util::counted<void> &pages)
|
|
||||||
{
|
{
|
||||||
uintptr_t phys = 0;
|
status_line status(L"Allocating initial page tables");
|
||||||
uintptr_t virt = bootproto::mem::linear_offset; // Start of offset-mapped area
|
|
||||||
size_t page_count = 64 * 1024; // 64 TiB of 1 GiB pages
|
|
||||||
constexpr size_t GiB = 0x40000000ull;
|
|
||||||
|
|
||||||
page_entry_iterator<2> iterator{virt, pml4, pages};
|
// include 1 extra for kernel PML4
|
||||||
|
static constexpr size_t tables_needed = pd_tables + extra_tables + 1;
|
||||||
|
|
||||||
while (true) {
|
void *addr = g_alloc.allocate_pages(tables_needed, alloc_type::page_table, true);
|
||||||
*iterator = phys | huge_page_flags;
|
m_bs->set_mem(addr, tables_needed * page_size, 0);
|
||||||
if (--page_count == 0)
|
m_table_pages = { .pointer = addr, .count = tables_needed };
|
||||||
break;
|
|
||||||
|
|
||||||
iterator.increment();
|
create_kernel_tables();
|
||||||
phys += GiB;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
add_kernel_pds(page_table *pml4, util::counted<void> &pages)
|
|
||||||
{
|
|
||||||
constexpr unsigned start = arch::kernel_root_index;
|
|
||||||
constexpr unsigned end = arch::table_entries;
|
|
||||||
|
|
||||||
for (unsigned i = start; i < end; ++i)
|
|
||||||
pml4->set(i, pop_pages(pages, 1), table_flags);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
add_current_mappings(page_table *new_pml4)
|
pager::map_pages(
|
||||||
|
uintptr_t phys, uintptr_t virt, size_t count,
|
||||||
|
bool write_flag, bool exe_flag)
|
||||||
|
{
|
||||||
|
if (!count)
|
||||||
|
return;
|
||||||
|
|
||||||
|
page_entry_iterator<4> iterator {virt, *this};
|
||||||
|
|
||||||
|
uint64_t flags = page_flags;
|
||||||
|
if (!exe_flag) flags |= (1ull << 63); // set NX bit
|
||||||
|
if (write_flag) flags |= 2;
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
uint64_t entry = phys | flags;
|
||||||
|
*iterator = entry;
|
||||||
|
|
||||||
|
if (--count == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
iterator.increment();
|
||||||
|
phys += page_size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
pager::update_kernel_args(bootproto::args *args)
|
||||||
|
{
|
||||||
|
status_line status {L"Updating kernel args"};
|
||||||
|
args->pml4 = reinterpret_cast<void*>(m_pml4);
|
||||||
|
args->page_tables = m_table_pages;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
pager::add_current_mappings()
|
||||||
{
|
{
|
||||||
// Get the pointer to the current PML4
|
// Get the pointer to the current PML4
|
||||||
page_table *old_pml4 = 0;
|
page_table *old_pml4 = 0;
|
||||||
@@ -185,98 +206,49 @@ add_current_mappings(page_table *new_pml4)
|
|||||||
for (int i = 0; i < halfway; ++i) {
|
for (int i = 0; i < halfway; ++i) {
|
||||||
uint64_t entry = old_pml4->entries[i];
|
uint64_t entry = old_pml4->entries[i];
|
||||||
if (entry & 1)
|
if (entry & 1)
|
||||||
new_pml4->entries[i] = entry;
|
m_pml4->entries[i] = entry;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
page_table *
|
||||||
allocate_tables(bootproto::args *args)
|
pager::pop_pages(size_t count)
|
||||||
{
|
{
|
||||||
status_line status(L"Allocating initial page tables");
|
if (count > m_table_pages.count)
|
||||||
|
error::raise(uefi::status::out_of_resources, L"Page table cache empty", 0x7ab1e5);
|
||||||
|
|
||||||
static constexpr size_t pd_tables = 256; // number of pages for kernelspace PDs
|
page_table *next = reinterpret_cast<page_table*>(m_table_pages.pointer);
|
||||||
static constexpr size_t extra_tables = 64; // number of extra pages
|
m_table_pages.pointer = util::offset_pointer(m_table_pages.pointer, count*page_size);
|
||||||
|
m_table_pages.count -= count;
|
||||||
// number of pages for kernelspace PDs + PML4
|
return next;
|
||||||
static constexpr size_t kernel_tables = pd_tables + 1;
|
|
||||||
|
|
||||||
static constexpr size_t tables_needed = kernel_tables + extra_tables;
|
|
||||||
|
|
||||||
void *addr = g_alloc.allocate_pages(tables_needed, alloc_type::page_table, true);
|
|
||||||
page_table *pml4 = reinterpret_cast<page_table*>(addr);
|
|
||||||
|
|
||||||
args->pml4 = pml4;
|
|
||||||
args->page_tables = { .pointer = pml4 + 1, .count = tables_needed - 1 };
|
|
||||||
|
|
||||||
console::print(L" First page (pml4) at: 0x%lx\r\n", pml4);
|
|
||||||
|
|
||||||
add_kernel_pds(pml4, args->page_tables);
|
|
||||||
add_offset_mappings(pml4, args->page_tables);
|
|
||||||
|
|
||||||
//console::print(L" Set up initial mappings, %d spare tables.\r\n", args->table_count);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename E>
|
|
||||||
constexpr bool has_flag(E set, E flag) {
|
|
||||||
return
|
|
||||||
(static_cast<uint64_t>(set) & static_cast<uint64_t>(flag)) ==
|
|
||||||
static_cast<uint64_t>(flag);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
map_pages(
|
pager::create_kernel_tables()
|
||||||
bootproto::args *args,
|
|
||||||
uintptr_t phys, uintptr_t virt,
|
|
||||||
size_t count, bool write_flag, bool exe_flag)
|
|
||||||
{
|
{
|
||||||
if (!count)
|
m_pml4 = pop_pages(1);
|
||||||
return;
|
page_table *pds = pop_pages(pd_tables);
|
||||||
|
|
||||||
paging::page_table *pml4 =
|
// Add PDs for all of high memory into the PML4
|
||||||
reinterpret_cast<paging::page_table*>(args->pml4);
|
constexpr unsigned start = arch::kernel_root_index;
|
||||||
|
constexpr unsigned end = arch::table_entries;
|
||||||
|
for (unsigned i = start; i < end; ++i)
|
||||||
|
m_pml4->set(i, &pds[i - start], table_flags);
|
||||||
|
|
||||||
page_entry_iterator<4> iterator{virt, pml4, args->page_tables};
|
// Add the linear offset-mapped area
|
||||||
|
uintptr_t phys = 0;
|
||||||
uint64_t flags = page_flags;
|
uintptr_t virt_base = bootproto::mem::linear_offset;
|
||||||
if (!exe_flag)
|
size_t page_count = 64 * 1024; // 64 TiB of 1 GiB pages
|
||||||
flags |= (1ull << 63); // set NX bit
|
constexpr size_t GiB = 0x40000000ull;
|
||||||
if (write_flag)
|
|
||||||
flags |= 2;
|
|
||||||
|
|
||||||
|
page_entry_iterator<2> iterator {virt_base, *this};
|
||||||
while (true) {
|
while (true) {
|
||||||
*iterator = phys | flags;
|
*iterator = phys | huge_page_flags;
|
||||||
if (--count == 0)
|
if (--page_count == 0)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
iterator.increment();
|
iterator.increment();
|
||||||
phys += page_size;
|
phys += GiB;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
map_section(
|
|
||||||
bootproto::args *args,
|
|
||||||
const bootproto::program_section §ion)
|
|
||||||
{
|
|
||||||
using bootproto::section_flags;
|
|
||||||
|
|
||||||
map_pages(
|
|
||||||
args,
|
|
||||||
section.phys_addr,
|
|
||||||
section.virt_addr,
|
|
||||||
memory::bytes_to_pages(section.size),
|
|
||||||
has_flag(section.type, section_flags::write),
|
|
||||||
has_flag(section.type, section_flags::execute));
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
map_program(
|
|
||||||
bootproto::args *args,
|
|
||||||
bootproto::program &program)
|
|
||||||
{
|
|
||||||
for (auto §ion : program.sections)
|
|
||||||
paging::map_section(args, section);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace paging
|
} // namespace paging
|
||||||
} // namespace boot
|
} // namespace boot
|
||||||
|
|||||||
@@ -3,60 +3,67 @@
|
|||||||
/// Page table structure and related definitions
|
/// Page table structure and related definitions
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <uefi/boot_services.h>
|
#include <uefi/boot_services.h>
|
||||||
#include <bootproto/kernel.h>
|
|
||||||
|
namespace bootproto {
|
||||||
|
struct args;
|
||||||
|
}
|
||||||
|
|
||||||
namespace boot {
|
namespace boot {
|
||||||
namespace paging {
|
namespace paging {
|
||||||
|
|
||||||
/// Struct to allow easy accessing of a memory page being used as a page table.
|
struct page_table;
|
||||||
struct page_table
|
|
||||||
|
class pager
|
||||||
{
|
{
|
||||||
uint64_t entries[512];
|
public:
|
||||||
|
static constexpr size_t pd_tables = 256; // number of pages for kernelspace PDs
|
||||||
|
static constexpr size_t extra_tables = 64; // number of extra pages
|
||||||
|
|
||||||
inline page_table * get(int i, uint16_t *flags = nullptr) const {
|
pager(uefi::boot_services *bs);
|
||||||
uint64_t entry = entries[i];
|
|
||||||
if ((entry & 1) == 0) return nullptr;
|
/// Map physical memory pages to virtual addresses in the given page tables.
|
||||||
if (flags) *flags = entry & 0xfff;
|
/// \arg phys The physical address of the pages to map
|
||||||
return reinterpret_cast<page_table *>(entry & ~0xfffull);
|
/// \arg virt The virtual address at which to map the pages
|
||||||
|
/// \arg count The number of pages to map
|
||||||
|
/// \arg write_flag If true, mark the pages writeable
|
||||||
|
/// \arg exe_flag If true, mark the pages executable
|
||||||
|
void map_pages(
|
||||||
|
uintptr_t phys,
|
||||||
|
uintptr_t virt,
|
||||||
|
size_t count,
|
||||||
|
bool write_flag,
|
||||||
|
bool exe_flag);
|
||||||
|
|
||||||
|
/// Update the kernel args structure before handing it off to the kernel
|
||||||
|
void update_kernel_args(bootproto::args *args);
|
||||||
|
|
||||||
|
/// Copy existing page table entries from the UEFI PML4 into our new PML4.
|
||||||
|
/// Does not do a deep copy - the new PML4 is updated to point to the
|
||||||
|
/// existing next-level page tables in the current PML4.
|
||||||
|
void add_current_mappings();
|
||||||
|
|
||||||
|
/// Write the pager's PML4 pointer to CR3
|
||||||
|
inline void install() const {
|
||||||
|
asm volatile ( "mov %0, %%cr3" :: "r" (m_pml4) );
|
||||||
|
__sync_synchronize();
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void set(int i, void *p, uint16_t flags) {
|
private:
|
||||||
entries[i] = reinterpret_cast<uint64_t>(p) | (flags & 0xfff);
|
template <unsigned D>
|
||||||
}
|
friend class page_entry_iterator;
|
||||||
|
|
||||||
|
/// Get `count` table pages from the cache
|
||||||
|
page_table * pop_pages(size_t count);
|
||||||
|
|
||||||
|
/// Allocate the kernel PML4 and PD tables out of the cache, and add the
|
||||||
|
/// linear offset mappings to them
|
||||||
|
void create_kernel_tables();
|
||||||
|
|
||||||
|
uefi::boot_services *m_bs;
|
||||||
|
util::counted<void> m_table_pages;
|
||||||
|
page_table *m_pml4;
|
||||||
|
page_table *m_kernel_pds;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Allocate memory to be used for initial page tables. Initial offset-mapped
|
|
||||||
/// page tables are pre-filled. All pages are saved as a module in kernel args
|
|
||||||
/// and kernel args' `page_table_cache` and `num_free_tables` are updated with
|
|
||||||
/// the leftover space.
|
|
||||||
/// \arg args The kernel args struct, used for the page table cache and pml4
|
|
||||||
void allocate_tables(bootproto::args *args);
|
|
||||||
|
|
||||||
/// Copy existing page table entries to a new page table. Does not do a deep
|
|
||||||
/// copy - the new PML4 is updated to point to the existing next-level page
|
|
||||||
/// tables in the current PML4.
|
|
||||||
/// \arg new_pml4 The new PML4 to copy into
|
|
||||||
void add_current_mappings(page_table *new_pml4);
|
|
||||||
|
|
||||||
/// Map physical memory pages to virtual addresses in the given page tables.
|
|
||||||
/// \arg args The kernel args struct, used for the page table cache and pml4
|
|
||||||
/// \arg phys The physical address of the pages to map
|
|
||||||
/// \arg virt The virtual address at which to map the pages
|
|
||||||
/// \arg count The number of pages to map
|
|
||||||
/// \arg write_flag If true, mark the pages writeable
|
|
||||||
/// \arg exe_flag If true, mark the pages executable
|
|
||||||
void map_pages(
|
|
||||||
bootproto::args *args,
|
|
||||||
uintptr_t phys, uintptr_t virt,
|
|
||||||
size_t count, bool write_flag, bool exe_flag);
|
|
||||||
|
|
||||||
/// Map the sections of a program in physical memory to their virtual memory
|
|
||||||
/// addresses in the given page tables.
|
|
||||||
/// \arg args The kernel args struct, used for the page table cache and pml4
|
|
||||||
/// \arg program The program to load
|
|
||||||
void map_program(
|
|
||||||
bootproto::args *args,
|
|
||||||
bootproto::program &program);
|
|
||||||
|
|
||||||
} // namespace paging
|
} // namespace paging
|
||||||
} // namespace boot
|
} // namespace boot
|
||||||
|
|||||||
@@ -7,10 +7,10 @@ uint32_t *apic_icr = reinterpret_cast<uint32_t*>(0xffffc000fee00300);
|
|||||||
void const *symbol_table = nullptr;
|
void const *symbol_table = nullptr;
|
||||||
|
|
||||||
void
|
void
|
||||||
install(uintptr_t entrypoint, const void *symbol_data)
|
install(uintptr_t entrypoint, util::const_buffer symbol_data)
|
||||||
{
|
{
|
||||||
IDT::set_nmi_handler(entrypoint);
|
IDT::set_nmi_handler(entrypoint);
|
||||||
symbol_table = symbol_data;
|
symbol_table = symbol_data.pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace panic
|
} // namespace panic
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include <util/counted.h>
|
||||||
#include "cpu.h"
|
#include "cpu.h"
|
||||||
|
|
||||||
namespace panic {
|
namespace panic {
|
||||||
@@ -47,8 +49,8 @@ inline void panic(
|
|||||||
|
|
||||||
/// Install a panic handler.
|
/// Install a panic handler.
|
||||||
/// \arg entrypoint Virtual address of the panic handler's entrypoint
|
/// \arg entrypoint Virtual address of the panic handler's entrypoint
|
||||||
/// \arg symbol_data Pointer to the symbol table data
|
/// \arg symbol_data Symbol table data
|
||||||
void install(uintptr_t entrypoint, const void *symbol_data);
|
void install(uintptr_t entrypoint, util::const_buffer symbol_data);
|
||||||
|
|
||||||
} // namespace panic
|
} // namespace panic
|
||||||
|
|
||||||
|
|||||||
@@ -32,9 +32,8 @@ void load_init_server(bootproto::program &program, uintptr_t modules_address);
|
|||||||
void
|
void
|
||||||
kernel_main(bootproto::args *args)
|
kernel_main(bootproto::args *args)
|
||||||
{
|
{
|
||||||
if (args->panic) {
|
if (args->panic_handler) {
|
||||||
const void *syms = util::offset_pointer(args->symbol_table, mem::linear_offset);
|
panic::install(args->panic_handler, args->symbol_table);
|
||||||
panic::install(args->panic->entrypoint, syms);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
logger_init();
|
logger_init();
|
||||||
@@ -75,7 +74,7 @@ kernel_main(bootproto::args *args)
|
|||||||
smp::ready();
|
smp::ready();
|
||||||
|
|
||||||
// Load the init server
|
// Load the init server
|
||||||
load_init_server(*args->init, args->modules);
|
load_init_server(args->init, args->init_modules);
|
||||||
|
|
||||||
sched->start();
|
sched->start();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,20 +1,36 @@
|
|||||||
|
PHDRS
|
||||||
|
{
|
||||||
|
rodata PT_LOAD PHDRS FILEHDR FLAGS (4) /* read-only */;
|
||||||
|
text PT_LOAD ;
|
||||||
|
rwdata PT_LOAD ;
|
||||||
|
bss PT_LOAD ;
|
||||||
|
}
|
||||||
|
|
||||||
|
MEMORY
|
||||||
|
{
|
||||||
|
panic (rwxa) : ORIGIN = 0xFFFF800080000000, LENGTH = 256M
|
||||||
|
}
|
||||||
|
|
||||||
ENTRY(_panic_entry)
|
ENTRY(_panic_entry)
|
||||||
|
|
||||||
SECTIONS
|
SECTIONS
|
||||||
{
|
{
|
||||||
. = 0xFFFF800080000000;
|
.rodata ORIGIN(panic) + SIZEOF_HEADERS : {
|
||||||
|
|
||||||
.text ALIGN(4096) : {
|
|
||||||
*(.text*)
|
|
||||||
}
|
|
||||||
|
|
||||||
.data ALIGN(4096) : {
|
|
||||||
*(.data*)
|
|
||||||
*(.rodata*)
|
*(.rodata*)
|
||||||
}
|
} :rodata
|
||||||
|
|
||||||
.bss ALIGN(4096) : {
|
.text ALIGN(4K) : {
|
||||||
|
*(.text*)
|
||||||
|
} :text
|
||||||
|
|
||||||
|
.data ALIGN(4K) : {
|
||||||
|
*(.data*)
|
||||||
|
*(.init_array*)
|
||||||
|
} :rwdata
|
||||||
|
|
||||||
|
.bss ALIGN(4K) : {
|
||||||
__bss_start = .;
|
__bss_start = .;
|
||||||
*(.bss*)
|
*(.bss*)
|
||||||
__bss_end = .;
|
__bss_end = .;
|
||||||
}
|
} :bss
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -129,13 +129,13 @@ struct args
|
|||||||
util::counted<void> page_tables;
|
util::counted<void> page_tables;
|
||||||
util::counted<mem_entry> mem_map;
|
util::counted<mem_entry> mem_map;
|
||||||
util::counted<frame_block> frame_blocks;
|
util::counted<frame_block> frame_blocks;
|
||||||
|
|
||||||
program *kernel;
|
|
||||||
program *init;
|
|
||||||
program *panic;
|
|
||||||
allocation_register *allocations;
|
allocation_register *allocations;
|
||||||
uintptr_t modules;
|
|
||||||
void const *symbol_table;
|
uintptr_t panic_handler;
|
||||||
|
util::buffer symbol_table;
|
||||||
|
|
||||||
|
program init;
|
||||||
|
uintptr_t init_modules;
|
||||||
|
|
||||||
void *runtime_services;
|
void *runtime_services;
|
||||||
void *acpi_table;
|
void *acpi_table;
|
||||||
|
|||||||
43
src/user/srv.init/init.ld
Normal file
43
src/user/srv.init/init.ld
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
PHDRS
|
||||||
|
{
|
||||||
|
rodata PT_LOAD PHDRS FILEHDR FLAGS (4) /* read-only */;
|
||||||
|
text PT_LOAD ;
|
||||||
|
rwdata PT_LOAD ;
|
||||||
|
bss PT_LOAD ;
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTIONS
|
||||||
|
{
|
||||||
|
. = 0x20000000 + SIZEOF_HEADERS ;
|
||||||
|
|
||||||
|
.rodata : {
|
||||||
|
*(.rodata*)
|
||||||
|
} :rodata
|
||||||
|
|
||||||
|
.text ALIGN(4K) : {
|
||||||
|
*(.text*)
|
||||||
|
} :text
|
||||||
|
|
||||||
|
.data ALIGN(4K) : {
|
||||||
|
*(.data*)
|
||||||
|
} :rwdata
|
||||||
|
|
||||||
|
.init_array : {
|
||||||
|
*(.init_array*)
|
||||||
|
} :rwdata
|
||||||
|
|
||||||
|
.got : {
|
||||||
|
*(.got*)
|
||||||
|
} :rwdata
|
||||||
|
|
||||||
|
.bss ALIGN(4K) : {
|
||||||
|
__bss_start = .;
|
||||||
|
*(.bss*)
|
||||||
|
__bss_end = .;
|
||||||
|
} :bss
|
||||||
|
|
||||||
|
/DISCARD/ : {
|
||||||
|
*(.gcc_except_table*)
|
||||||
|
*(.eh_frame*)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,6 +4,7 @@ init = module("srv.init",
|
|||||||
targets = [ "user" ],
|
targets = [ "user" ],
|
||||||
deps = [ "libc", "elf", "bootproto", "zstd" ],
|
deps = [ "libc", "elf", "bootproto", "zstd" ],
|
||||||
description = "Init server",
|
description = "Init server",
|
||||||
|
ld_script = "init.ld",
|
||||||
sources = [
|
sources = [
|
||||||
"j6romfs.cpp",
|
"j6romfs.cpp",
|
||||||
"loader.cpp",
|
"loader.cpp",
|
||||||
|
|||||||
Reference in New Issue
Block a user