[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,5 +1,6 @@
|
||||
#include "kernel_memory.h"
|
||||
|
||||
#include "allocator.h"
|
||||
#include "console.h"
|
||||
#include "error.h"
|
||||
#include "loader.h"
|
||||
@@ -11,6 +12,7 @@
|
||||
namespace boot {
|
||||
namespace paging {
|
||||
|
||||
using memory::alloc_type;
|
||||
using memory::page_size;
|
||||
using ::memory::pml4e_kernel;
|
||||
using ::memory::table_entries;
|
||||
@@ -54,23 +56,33 @@ constexpr uint64_t huge_page_flags = 0x18b;
|
||||
/// Page table entry flags for entries pointing at another table
|
||||
constexpr uint64_t table_flags = 0x003;
|
||||
|
||||
|
||||
inline void *
|
||||
pop_pages(counted<void> &pages, size_t count)
|
||||
{
|
||||
if (count > pages.count)
|
||||
error::raise(uefi::status::out_of_resources, L"Page table cache empty", 0x7ab1e5);
|
||||
|
||||
void *next = pages.pointer;
|
||||
pages.pointer = offset_ptr<void>(pages.pointer, count*page_size);
|
||||
pages.count -= count;
|
||||
return next;
|
||||
}
|
||||
|
||||
/// Iterator over page table entries.
|
||||
template <unsigned D = 4>
|
||||
class page_entry_iterator
|
||||
{
|
||||
public:
|
||||
/// Constructor.
|
||||
/// \arg virt Virtual address this iterator is starting at
|
||||
/// \arg pml4 Root of the page tables to iterate
|
||||
/// \arg page_cache Pointer to pages that can be used for page tables
|
||||
/// \arg page_count Number of pages pointed to by `page_cache`
|
||||
/// \arg virt Virtual address this iterator is starting at
|
||||
/// \arg pml4 Root of the page tables to iterate
|
||||
/// \arg pages Cache of usable table pages
|
||||
page_entry_iterator(
|
||||
uintptr_t virt,
|
||||
page_table *pml4,
|
||||
void *&page_cache,
|
||||
size_t &cache_count) :
|
||||
m_page_cache(page_cache),
|
||||
m_cache_count(cache_count)
|
||||
counted<void> &pages) :
|
||||
m_pages(pages)
|
||||
{
|
||||
m_table[0] = pml4;
|
||||
for (unsigned i = 0; i < D; ++i) {
|
||||
@@ -117,12 +129,7 @@ private:
|
||||
uint64_t & parent_ent = entry(level - 1);
|
||||
|
||||
if (!(parent_ent & 1)) {
|
||||
if (!m_cache_count--)
|
||||
error::raise(uefi::status::out_of_resources, L"Page table cache empty", 0x7ab1e5);
|
||||
|
||||
page_table *table = reinterpret_cast<page_table*>(m_page_cache);
|
||||
m_page_cache = offset_ptr<void>(m_page_cache, page_size);
|
||||
|
||||
page_table *table = reinterpret_cast<page_table*>(pop_pages(m_pages, 1));
|
||||
parent_ent = (reinterpret_cast<uintptr_t>(table) & ~0xfffull) | table_flags;
|
||||
m_table[level] = table;
|
||||
} else {
|
||||
@@ -130,29 +137,25 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
void *&m_page_cache;
|
||||
size_t &m_cache_count;
|
||||
counted<void> &m_pages;
|
||||
page_table *m_table[D];
|
||||
uint16_t m_index[D];
|
||||
};
|
||||
|
||||
|
||||
static void
|
||||
add_offset_mappings(page_table *pml4, void *&page_cache, size_t &num_pages)
|
||||
add_offset_mappings(page_table *pml4, counted<void> &pages)
|
||||
{
|
||||
uintptr_t phys = 0;
|
||||
uintptr_t virt = ::memory::page_offset; // Start of offset-mapped area
|
||||
size_t pages = 64 * 1024; // 64 TiB of 1 GiB pages
|
||||
size_t page_count = 64 * 1024; // 64 TiB of 1 GiB pages
|
||||
constexpr size_t GiB = 0x40000000ull;
|
||||
|
||||
page_entry_iterator<2> iterator{
|
||||
virt, pml4,
|
||||
page_cache,
|
||||
num_pages};
|
||||
page_entry_iterator<2> iterator{virt, pml4, pages};
|
||||
|
||||
while (true) {
|
||||
*iterator = phys | huge_page_flags;
|
||||
if (--pages == 0)
|
||||
if (--page_count == 0)
|
||||
break;
|
||||
|
||||
iterator.increment();
|
||||
@@ -161,13 +164,10 @@ add_offset_mappings(page_table *pml4, void *&page_cache, size_t &num_pages)
|
||||
}
|
||||
|
||||
static void
|
||||
add_kernel_pds(page_table *pml4, void *&page_cache, size_t &num_pages)
|
||||
add_kernel_pds(page_table *pml4, counted<void> &pages)
|
||||
{
|
||||
for (unsigned i = pml4e_kernel; i < table_entries; ++i) {
|
||||
pml4->set(i, page_cache, table_flags);
|
||||
page_cache = offset_ptr<void>(page_cache, page_size);
|
||||
num_pages--;
|
||||
}
|
||||
for (unsigned i = pml4e_kernel; i < table_entries; ++i)
|
||||
pml4->set(i, pop_pages(pages, 1), table_flags);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -186,7 +186,7 @@ add_current_mappings(page_table *new_pml4)
|
||||
}
|
||||
|
||||
void
|
||||
allocate_tables(kernel::init::args *args, uefi::boot_services *bs)
|
||||
allocate_tables(kernel::init::args *args)
|
||||
{
|
||||
status_line status(L"Allocating initial page tables");
|
||||
|
||||
@@ -198,28 +198,16 @@ allocate_tables(kernel::init::args *args, uefi::boot_services *bs)
|
||||
|
||||
static constexpr size_t tables_needed = kernel_tables + extra_tables;
|
||||
|
||||
void *addr = nullptr;
|
||||
try_or_raise(
|
||||
bs->allocate_pages(
|
||||
uefi::allocate_type::any_pages,
|
||||
uefi::memory_type::loader_data,
|
||||
tables_needed,
|
||||
&addr),
|
||||
L"Error allocating page table pages.");
|
||||
|
||||
bs->set_mem(addr, tables_needed*page_size, 0);
|
||||
|
||||
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->table_pages = tables_needed;
|
||||
args->table_count = tables_needed - 1;
|
||||
args->page_tables = offset_ptr<void>(addr, page_size);
|
||||
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, args->table_count);
|
||||
add_offset_mappings(pml4, args->page_tables, args->table_count);
|
||||
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);
|
||||
}
|
||||
@@ -243,10 +231,7 @@ map_pages(
|
||||
paging::page_table *pml4 =
|
||||
reinterpret_cast<paging::page_table*>(args->pml4);
|
||||
|
||||
page_entry_iterator<4> iterator{
|
||||
virt, pml4,
|
||||
args->page_tables,
|
||||
args->table_count};
|
||||
page_entry_iterator<4> iterator{virt, pml4, args->page_tables};
|
||||
|
||||
uint64_t flags = page_flags;
|
||||
if (!exe_flag)
|
||||
|
||||
Reference in New Issue
Block a user