mirror of
https://github.com/justinian/jsix.git
synced 2025-12-10 00:14:32 -08:00
Allow for 2MiB large pages
This commit is contained in:
@@ -4,6 +4,7 @@
|
||||
#include "page_manager.h"
|
||||
|
||||
const unsigned efi_page_size = 0x1000;
|
||||
const unsigned ident_page_flags = 0xf; // TODO: set to 0xb when user/kernel page tables are better sorted
|
||||
|
||||
enum class efi_memory_type : uint32_t
|
||||
{
|
||||
@@ -306,7 +307,7 @@ copy_new_table(page_table *base, unsigned index, page_table *new_table)
|
||||
for (int i = 0; i < 512; ++i) new_table->entries[i] = 0;
|
||||
}
|
||||
|
||||
base->entries[index] = reinterpret_cast<uint64_t>(new_table) | 0xb;
|
||||
base->entries[index] = reinterpret_cast<uint64_t>(new_table) | ident_page_flags;
|
||||
}
|
||||
|
||||
static uint64_t
|
||||
@@ -363,7 +364,7 @@ check_needs_page_ident(page_table *table, unsigned index, page_table **free_page
|
||||
|
||||
page_table *new_table = (*free_pages)++;
|
||||
for (int i=0; i<512; ++i) new_table->entries[i] = 0;
|
||||
table->entries[index] = reinterpret_cast<uint64_t>(new_table) | 0xb;
|
||||
table->entries[index] = reinterpret_cast<uint64_t>(new_table) | ident_page_flags;
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -390,12 +391,24 @@ page_in_ident(
|
||||
tables[1]->entries[idx[1]] & ~0xfffull);
|
||||
|
||||
for (; idx[2] < 512; idx[2] += 1, idx[3] = 0) {
|
||||
if (idx[3] == 0 &&
|
||||
count >= 512 &&
|
||||
tables[2]->get(idx[2]) == nullptr) {
|
||||
// Do a 2MiB page instead
|
||||
tables[2]->entries[idx[2]] = phys_addr | 0x80 | ident_page_flags;
|
||||
|
||||
phys_addr += page_manager::page_size * 512;
|
||||
count -= 512;
|
||||
if (count == 0) return pages_consumed;
|
||||
continue;
|
||||
}
|
||||
|
||||
pages_consumed += check_needs_page_ident(tables[2], idx[2], &free_pages);
|
||||
tables[3] = reinterpret_cast<page_table *>(
|
||||
tables[2]->entries[idx[2]] & ~0xfffull);
|
||||
|
||||
for (; idx[3] < 512; idx[3] += 1) {
|
||||
tables[3]->entries[idx[3]] = phys_addr | 0xb;
|
||||
tables[3]->entries[idx[3]] = phys_addr | ident_page_flags;
|
||||
phys_addr += page_manager::page_size;
|
||||
if (--count == 0) return pages_consumed;
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include "kutil/assert.h"
|
||||
#include "kutil/memory_manager.h"
|
||||
#include "console.h"
|
||||
#include "log.h"
|
||||
#include "page_manager.h"
|
||||
|
||||
@@ -253,6 +254,12 @@ page_manager::dump_blocks()
|
||||
page_block::dump(m_free, "free", true);
|
||||
}
|
||||
|
||||
void
|
||||
page_manager::dump_pml4()
|
||||
{
|
||||
get_pml4()->dump();
|
||||
}
|
||||
|
||||
page_block *
|
||||
page_manager::get_block()
|
||||
{
|
||||
@@ -480,36 +487,47 @@ page_manager::unmap_pages(void* address, size_t count)
|
||||
}
|
||||
|
||||
void
|
||||
page_manager::check_needs_page(page_table *table, unsigned index)
|
||||
page_manager::check_needs_page(page_table *table, unsigned index, bool user)
|
||||
{
|
||||
if ((table->entries[index] & 0x1) == 1) return;
|
||||
|
||||
page_table *new_table = get_table_page();
|
||||
for (int i=0; i<512; ++i) new_table->entries[i] = 0;
|
||||
table->entries[index] = pt_to_phys(new_table) | 0xb;
|
||||
table->entries[index] = pt_to_phys(new_table) | (user ? 0xf : 0xb);
|
||||
}
|
||||
|
||||
void
|
||||
page_manager::page_in(page_table *pml4, addr_t phys_addr, addr_t virt_addr, size_t count)
|
||||
page_manager::page_in(page_table *pml4, addr_t phys_addr, addr_t virt_addr, size_t count, bool user)
|
||||
{
|
||||
page_table_indices idx{virt_addr};
|
||||
page_table *tables[4] = {pml4, nullptr, nullptr, nullptr};
|
||||
|
||||
for (; idx[0] < 512; idx[0] += 1) {
|
||||
check_needs_page(tables[0], idx[0]);
|
||||
check_needs_page(tables[0], idx[0], user);
|
||||
tables[1] = tables[0]->get(idx[0]);
|
||||
|
||||
for (; idx[1] < 512; idx[1] += 1, idx[2] = 0, idx[3] = 0) {
|
||||
check_needs_page(tables[1], idx[1]);
|
||||
check_needs_page(tables[1], idx[1], user);
|
||||
tables[2] = tables[1]->get(idx[1]);
|
||||
|
||||
for (; idx[2] < 512; idx[2] += 1, idx[3] = 0) {
|
||||
check_needs_page(tables[2], idx[2]);
|
||||
if (idx[3] == 0 &&
|
||||
count >= 512 &&
|
||||
tables[2]->get(idx[2]) == nullptr) {
|
||||
// Do a 2MiB page instead
|
||||
tables[2]->entries[idx[2]] = phys_addr | (user ? 0x8f : 0x8b);
|
||||
phys_addr += page_size * 512;
|
||||
count -= 512;
|
||||
if (count == 0) return;
|
||||
continue;
|
||||
}
|
||||
|
||||
check_needs_page(tables[2], idx[2], user);
|
||||
tables[3] = tables[2]->get(idx[2]);
|
||||
|
||||
for (; idx[3] < 512; idx[3] += 1) {
|
||||
tables[3]->entries[idx[3]] = phys_addr | 0xb;
|
||||
phys_addr += page_manager::page_size;
|
||||
tables[3]->entries[idx[3]] = phys_addr | (user ? 0xf : 0xb);
|
||||
phys_addr += page_size;
|
||||
if (--count == 0) return;
|
||||
}
|
||||
}
|
||||
@@ -573,25 +591,25 @@ page_manager::pop_pages(size_t count, addr_t *address)
|
||||
void
|
||||
page_table::dump(int level, uint64_t offset)
|
||||
{
|
||||
log::info(logs::memory, "Level %d page table @ %lx (off %lx):", level, this, offset);
|
||||
console *cons = console::get();
|
||||
|
||||
cons->printf("\nLevel %d page table @ %lx (off %lx):\n", level, this, offset);
|
||||
for (int i=0; i<512; ++i) {
|
||||
uint64_t ent = entries[i];
|
||||
if (ent == 0) continue;
|
||||
|
||||
if ((ent & 0x1) == 0) {
|
||||
log::info(logs::memory, " %3d: %lx NOT PRESENT", i, ent);
|
||||
cons->printf(" %3d: %016lx NOT PRESENT\n", i, ent);
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((level == 2 || level == 3) && (ent & 0x80) == 0x80) {
|
||||
log::info(logs::memory, " %3d: %lx -> Large page at %lx",
|
||||
i, ent, ent & ~0xfffull);
|
||||
cons->printf(" %3d: %016lx -> Large page at %016lx\n", i, ent, ent & ~0xfffull);
|
||||
continue;
|
||||
} else if (level == 1) {
|
||||
log::info(logs::memory, " %3d: %lx -> Page at %lx",
|
||||
i, ent, ent & ~0xfffull);
|
||||
cons->printf(" %3d: %016lx -> Page at %016lx\n", i, ent, ent & ~0xfffull);
|
||||
} else {
|
||||
log::info(logs::memory, " %3d: %lx -> Level %d table at %lx",
|
||||
cons->printf(" %3d: %016lx -> Level %d table at %016lx\n",
|
||||
i, ent, level - 1, (ent & ~0xfffull) + offset);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -70,6 +70,9 @@ public:
|
||||
/// Log the current free/used block lists.
|
||||
void dump_blocks();
|
||||
|
||||
/// Dump the current PML4 to the console
|
||||
void dump_pml4();
|
||||
|
||||
/// Get the system page manager.
|
||||
/// \returns A pointer to the system page manager
|
||||
static page_manager * get();
|
||||
@@ -127,18 +130,21 @@ private:
|
||||
/// it.
|
||||
/// \arg base Existing page table being indexed into
|
||||
/// \arg i Index into the existing table to check
|
||||
void check_needs_page(page_table *base, unsigned i);
|
||||
/// \art user True if this is a userspace mapping
|
||||
void check_needs_page(page_table *base, unsigned i, bool user);
|
||||
|
||||
/// Low-level routine for mapping a number of pages into the given page table.
|
||||
/// \arg pml4 The root page table to map into
|
||||
/// \arg phys_addr The starting physical address of the pages to be mapped
|
||||
/// \arg virt_addr The starting virtual address ot the memory to be mapped
|
||||
/// \arg count The number of pages to map
|
||||
/// \art user True if this is a userspace mapping
|
||||
void page_in(
|
||||
page_table *pml4,
|
||||
addr_t phys_addr,
|
||||
addr_t virt_addr,
|
||||
size_t count);
|
||||
size_t count,
|
||||
bool user = true);
|
||||
|
||||
/// Low-level routine for unmapping a number of pages from the given page table.
|
||||
/// \arg pml4 The root page table for this mapping
|
||||
|
||||
Reference in New Issue
Block a user