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