[boot] Improve bootloader allocation accounting
The bootloader relied on the kernel to know which parts of memory to not allocate over. For the future shift of having the init process load other processes instead of the kernel, the bootloader needs a mechanism to just hand the kernel a list of allocations. This is now done through the new bootloader allocator, which all allocation goes through. Pool memory will not be tracked, and so can be overwritten - this means the args structure and its other structures like programs need to be handled right away, or copied by the kernel. - Add bootloader allocator - Implement a new linked-list based set of pages that act as allocation registers - Allow for operator new in the bootloader, which goes through the global allocator for pool memory - Split memory map and frame accouting code in the bootloader into separate memory_map.* files - Remove many includes that could be replaced by forward declaration in the bootloader - Add a new global template type, `counted`, which replaces the bootloader's `buffer` type, and updated kernel args structure to use it. - Move bootloader's pointer_manipulation.h to the global include dir - Make offset_iterator try to return references instead of pointers to make it more consistent with static array iteration - Implement a stub atexit() in the bootloader to satisfy clang
This commit is contained in:
@@ -1,13 +1,15 @@
|
||||
#include <uefi/boot_services.h>
|
||||
#include <uefi/types.h>
|
||||
|
||||
#include "loader.h"
|
||||
#include "allocator.h"
|
||||
#include "console.h"
|
||||
#include "elf.h"
|
||||
#include "error.h"
|
||||
#include "fs.h"
|
||||
#include "loader.h"
|
||||
#include "memory.h"
|
||||
#include "paging.h"
|
||||
#include "pointer_manipulation.h"
|
||||
#include "status.h"
|
||||
|
||||
namespace init = kernel::init;
|
||||
@@ -15,17 +17,18 @@ namespace init = kernel::init;
|
||||
namespace boot {
|
||||
namespace loader {
|
||||
|
||||
using memory::alloc_type;
|
||||
|
||||
buffer
|
||||
load_file(
|
||||
fs::file &disk,
|
||||
const wchar_t *name,
|
||||
const wchar_t *path,
|
||||
uefi::memory_type type)
|
||||
const wchar_t *path)
|
||||
{
|
||||
status_line status(L"Loading file", name);
|
||||
|
||||
fs::file file = disk.open(path);
|
||||
buffer b = file.load(type);
|
||||
buffer b = file.load();
|
||||
|
||||
//console::print(L" Loaded at: 0x%lx, %d bytes\r\n", b.data, b.size);
|
||||
return b;
|
||||
@@ -51,59 +54,55 @@ void
|
||||
load_program(
|
||||
init::program &program,
|
||||
const wchar_t *name,
|
||||
buffer data,
|
||||
uefi::boot_services *bs)
|
||||
buffer data)
|
||||
{
|
||||
status_line status(L"Loading program:", name);
|
||||
const elf::header *header = reinterpret_cast<const elf::header*>(data.data);
|
||||
const elf::header *header = reinterpret_cast<const elf::header*>(data.pointer);
|
||||
|
||||
if (data.size < sizeof(elf::header) || !is_elfheader_valid(header))
|
||||
if (data.count < sizeof(elf::header) || !is_elfheader_valid(header))
|
||||
error::raise(uefi::status::load_error, L"ELF file not valid");
|
||||
|
||||
size_t num_sections = 0;
|
||||
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);
|
||||
offset_ptr<elf::program_header>(data.pointer, offset);
|
||||
|
||||
if (pheader->type != elf::PT_LOAD)
|
||||
continue;
|
||||
|
||||
++num_sections;
|
||||
uintptr_t end = pheader->vaddr + pheader->mem_size;
|
||||
if (pheader->vaddr < prog_base) prog_base = pheader->vaddr;
|
||||
if (end > prog_end) prog_end = end;
|
||||
}
|
||||
|
||||
init::program_section *sections = new init::program_section [num_sections];
|
||||
program.sections = { .pointer = sections, .count = num_sections };
|
||||
|
||||
size_t total_size = prog_end - prog_base;
|
||||
size_t num_pages = memory::bytes_to_pages(total_size);
|
||||
void *pages = nullptr;
|
||||
void *pages = g_alloc.allocate_pages(num_pages, alloc_type::program, true);
|
||||
program.phys_base = reinterpret_cast<uintptr_t>(pages);
|
||||
|
||||
try_or_raise(
|
||||
bs->allocate_pages(uefi::allocate_type::any_pages,
|
||||
uefi::memory_type::loader_data, num_pages, &pages),
|
||||
L"Failed allocating space for program");
|
||||
|
||||
bs->set_mem(pages, total_size, 0);
|
||||
|
||||
program.base = prog_base;
|
||||
program.total_size = total_size;
|
||||
program.num_sections = 0;
|
||||
size_t next_section = 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);
|
||||
offset_ptr<elf::program_header>(data.pointer, offset);
|
||||
|
||||
if (pheader->type != elf::PT_LOAD)
|
||||
continue;
|
||||
|
||||
init::program_section §ion = program.sections[program.num_sections++];
|
||||
init::program_section §ion = program.sections[next_section++];
|
||||
|
||||
void *src_start = offset_ptr<void>(data.data, pheader->offset);
|
||||
void *src_start = offset_ptr<void>(data.pointer, pheader->offset);
|
||||
void *dest_start = offset_ptr<void>(pages, pheader->vaddr - prog_base);
|
||||
|
||||
bs->copy_mem(dest_start, src_start, pheader->file_size);
|
||||
g_alloc.copy(dest_start, src_start, pheader->file_size);
|
||||
section.phys_addr = reinterpret_cast<uintptr_t>(dest_start);
|
||||
section.virt_addr = pheader->vaddr;
|
||||
section.size = pheader->mem_size;
|
||||
@@ -114,9 +113,7 @@ load_program(
|
||||
}
|
||||
|
||||
void
|
||||
verify_kernel_header(
|
||||
init::program &program,
|
||||
uefi::boot_services *bs)
|
||||
verify_kernel_header(init::program &program)
|
||||
{
|
||||
status_line status(L"Verifying kernel header");
|
||||
|
||||
@@ -132,7 +129,7 @@ verify_kernel_header(
|
||||
if (header->version < init::min_header_version)
|
||||
error::raise(uefi::status::unsupported, L"Kernel header version not supported");
|
||||
|
||||
console::print(L" Loaded kernel vserion: %d.%d.%d %lx\r\n",
|
||||
console::print(L" Loaded kernel vserion: %d.%d.%d %x\r\n",
|
||||
header->version_major, header->version_minor, header->version_patch,
|
||||
header->version_gitsha);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user