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/types.h>
|
||||
|
||||
#include <bootproto/init.h>
|
||||
#include <elf/file.h>
|
||||
#include <elf/headers.h>
|
||||
#include <util/pointers.h>
|
||||
@@ -22,9 +21,7 @@ namespace loader {
|
||||
using memory::alloc_type;
|
||||
|
||||
util::buffer
|
||||
load_file(
|
||||
fs::file &disk,
|
||||
const wchar_t *path)
|
||||
load_file(fs::file &disk, const wchar_t *path)
|
||||
{
|
||||
status_line status(L"Loading file", path);
|
||||
|
||||
@@ -61,73 +58,108 @@ verify_kernel_header(elf::file &kernel, util::const_buffer data)
|
||||
header->version_gitsha);
|
||||
}
|
||||
|
||||
bootproto::program *
|
||||
load_program(
|
||||
fs::file &disk,
|
||||
const wchar_t *name,
|
||||
const descriptor &desc,
|
||||
bool verify)
|
||||
inline void
|
||||
elf_error(const elf::file &elf, util::const_buffer data)
|
||||
{
|
||||
status_line status(L"Loading program", name);
|
||||
auto *header = elf.header();
|
||||
console::print(L" progam size: %d\r\n", data.count);
|
||||
console::print(L" word size: %d\r\n", header->word_size);
|
||||
console::print(L" endianness: %d\r\n", header->endianness);
|
||||
console::print(L" ELF ident version: %d\r\n", header->ident_version);
|
||||
console::print(L" OS ABI: %d\r\n", header->os_abi);
|
||||
console::print(L" file type: %d\r\n", header->file_type);
|
||||
console::print(L" machine type: %d\r\n", header->machine_type);
|
||||
console::print(L" ELF version: %d\r\n", header->version);
|
||||
|
||||
util::const_buffer data = load_file(disk, desc.path);
|
||||
error::raise(uefi::status::load_error, L"ELF file not valid");
|
||||
}
|
||||
|
||||
elf::file program {data};
|
||||
if (!program.valid()) {
|
||||
auto *header = program.header();
|
||||
console::print(L" progam size: %d\r\n", data.count);
|
||||
console::print(L" word size: %d\r\n", header->word_size);
|
||||
console::print(L" endianness: %d\r\n", header->endianness);
|
||||
console::print(L" ELF ident version: %d\r\n", header->ident_version);
|
||||
console::print(L" OS ABI: %d\r\n", header->os_abi);
|
||||
console::print(L" file type: %d\r\n", header->file_type);
|
||||
console::print(L" machine type: %d\r\n", header->machine_type);
|
||||
console::print(L" ELF version: %d\r\n", header->version);
|
||||
inline uintptr_t
|
||||
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);
|
||||
}
|
||||
|
||||
error::raise(uefi::status::load_error, L"ELF file not valid");
|
||||
}
|
||||
|
||||
if (verify)
|
||||
verify_kernel_header(program, data);
|
||||
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;
|
||||
for (auto &seg : program.segments()) {
|
||||
for (auto &seg : elf.segments()) {
|
||||
if (seg.type == elf::segment_type::load)
|
||||
++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;
|
||||
for (auto &seg : program.segments()) {
|
||||
for (auto &seg : elf.segments()) {
|
||||
if (seg.type != elf::segment_type::load)
|
||||
continue;
|
||||
|
||||
bootproto::program_section §ion = sections[next_section++];
|
||||
|
||||
uintptr_t virt_addr = seg.vaddr;
|
||||
size_t mem_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.phys_addr = elf.base() + seg.offset;
|
||||
section.virt_addr = seg.vaddr;
|
||||
section.size = seg.mem_size;
|
||||
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;
|
||||
prog->sections = { .pointer = sections, .count = num_sections };
|
||||
prog->phys_base = program.base();
|
||||
prog->entrypoint = program.entrypoint();
|
||||
return prog;
|
||||
program.sections = { .pointer = sections, .count = num_sections };
|
||||
program.phys_base = elf.base();
|
||||
program.entrypoint = elf.entrypoint();
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user