MMU: Add functions to create and delete userspace page directories
This commit is contained in:
parent
c53bba0392
commit
31ea030c7f
@ -31,6 +31,7 @@ namespace MMU
|
||||
void flush_all();
|
||||
|
||||
Result<PageDirectory*> create_page_directory_for_userspace();
|
||||
Result<void> delete_userspace_page_directory(PageDirectory* directory);
|
||||
void setup_initial_page_directory();
|
||||
|
||||
PageDirectory* kernel_page_directory();
|
||||
|
@ -2,6 +2,7 @@
|
||||
#include "memory/MemoryManager.h"
|
||||
#include <luna/CString.h>
|
||||
#include <luna/Result.h>
|
||||
#include <luna/ScopeGuard.h>
|
||||
#include <luna/SystemError.h>
|
||||
|
||||
#pragma GCC push_options
|
||||
@ -50,11 +51,16 @@ namespace MMU
|
||||
return l4_table()->entries[l4_index(addr)];
|
||||
}
|
||||
|
||||
constexpr PageDirectory* raw_l3_table(u64 l4)
|
||||
{
|
||||
const u64 l3 = sign | (rindex << 39) | (rindex << 30) | (rindex << 21) | (l4 << 12);
|
||||
return (PageDirectory*)l3;
|
||||
}
|
||||
|
||||
constexpr PageDirectory* l3_table(u64 addr)
|
||||
{
|
||||
const u64 l4 = l4_index(addr);
|
||||
const u64 l3 = sign | (rindex << 39) | (rindex << 30) | (rindex << 21) | (l4 << 12);
|
||||
return (PageDirectory*)l3;
|
||||
return raw_l3_table(l4);
|
||||
}
|
||||
|
||||
constexpr u64 l3_index(u64 addr)
|
||||
@ -67,12 +73,17 @@ namespace MMU
|
||||
return l3_table(addr)->entries[l3_index(addr)];
|
||||
}
|
||||
|
||||
constexpr PageDirectory* raw_l2_table(u64 l4, u64 l3)
|
||||
{
|
||||
const u64 l2 = sign | (rindex << 39) | (rindex << 30) | (l4 << 21) | (l3 << 12);
|
||||
return (PageDirectory*)l2;
|
||||
}
|
||||
|
||||
constexpr PageDirectory* l2_table(u64 addr)
|
||||
{
|
||||
const u64 l4 = l4_index(addr);
|
||||
const u64 l3 = l3_index(addr);
|
||||
const u64 l2 = sign | (rindex << 39) | (rindex << 30) | (l4 << 21) | (l3 << 12);
|
||||
return (PageDirectory*)l2;
|
||||
return raw_l2_table(l4, l3);
|
||||
}
|
||||
|
||||
constexpr u64 l2_index(u64 addr)
|
||||
@ -85,13 +96,18 @@ namespace MMU
|
||||
return l2_table(addr)->entries[l2_index(addr)];
|
||||
}
|
||||
|
||||
constexpr PageDirectory* raw_l1_table(u64 l4, u64 l3, u64 l2)
|
||||
{
|
||||
const u64 l1 = sign | (rindex << 39) | (l4 << 30) | (l3 << 21) | (l2 << 12);
|
||||
return (PageDirectory*)l1;
|
||||
}
|
||||
|
||||
constexpr PageDirectory* l1_table(u64 addr)
|
||||
{
|
||||
const u64 l4 = l4_index(addr);
|
||||
const u64 l3 = l3_index(addr);
|
||||
const u64 l2 = l2_index(addr);
|
||||
const u64 l1 = sign | (rindex << 39) | (l4 << 30) | (l3 << 21) | (l2 << 12);
|
||||
return (PageDirectory*)l1;
|
||||
return raw_l1_table(l4, l3, l2);
|
||||
}
|
||||
|
||||
constexpr u64 l1_index(u64 addr)
|
||||
@ -270,6 +286,96 @@ namespace MMU
|
||||
flush_all();
|
||||
}
|
||||
|
||||
Result<PageDirectory*> create_page_directory_for_userspace()
|
||||
{
|
||||
u64 directory_virt = TRY(MemoryManager::alloc_for_kernel(1, MMU::ReadWrite | MMU::NoExecute));
|
||||
u64 directory_phys = MMU::get_physical(directory_virt).value();
|
||||
|
||||
PageDirectory* directory = (PageDirectory*)directory_virt;
|
||||
memset(directory, 0, ARCH_PAGE_SIZE);
|
||||
PageTableEntry& recursive_entry = directory->entries[rindex];
|
||||
recursive_entry.read_write = true;
|
||||
recursive_entry.present = true;
|
||||
recursive_entry.set_address(directory_phys);
|
||||
|
||||
directory->entries[511] = g_kernel_directory->entries[511];
|
||||
|
||||
// From now on, we're only going to use the physical address, since accessing the PageDirectory will be dealt
|
||||
// with using recursive mapping. So let's make sure we don't leak any VM.
|
||||
MemoryManager::unmap_weak_and_free_vm(directory_virt, 1);
|
||||
|
||||
return (PageDirectory*)directory_phys;
|
||||
}
|
||||
|
||||
Result<void> delete_userspace_page_directory(PageDirectory* directory)
|
||||
{
|
||||
check(directory);
|
||||
|
||||
// Needed in order to access page tables using the recursive mapping system.
|
||||
switch_page_directory(directory);
|
||||
|
||||
auto guard = make_scope_guard([&] {
|
||||
check(g_kernel_directory);
|
||||
switch_page_directory(g_kernel_directory);
|
||||
MemoryManager::free_frame((u64)directory);
|
||||
});
|
||||
|
||||
PageDirectory* table = l4_table();
|
||||
|
||||
// Let's iterate over every top-level entry, skipping the last two entries (recursive mapping and kernel pages)
|
||||
for (u64 i = 0; i < 510; i++)
|
||||
{
|
||||
PageTableEntry& l4 = table->entries[i];
|
||||
if (!l4.present) continue;
|
||||
|
||||
PageDirectory* pdp = raw_l3_table(i);
|
||||
|
||||
for (u64 j = 0; j < 512; j++)
|
||||
{
|
||||
PageTableEntry& l3 = pdp->entries[j];
|
||||
if (!l3.present) continue;
|
||||
if (l3.larger_pages)
|
||||
{
|
||||
// FIXME: Maybe we shouldn't delete some pages in an address space, such as shared memory.
|
||||
TRY(MemoryManager::free_frame(l3.get_address()));
|
||||
}
|
||||
|
||||
PageDirectory* pd = raw_l2_table(i, j);
|
||||
|
||||
for (u64 k = 0; k < 512; k++)
|
||||
{
|
||||
PageTableEntry& l2 = pd->entries[k];
|
||||
if (!l2.present) continue;
|
||||
if (l2.larger_pages)
|
||||
{
|
||||
// FIXME: Maybe we shouldn't delete some pages in an address space, such as shared memory.
|
||||
TRY(MemoryManager::free_frame(l2.get_address()));
|
||||
}
|
||||
|
||||
PageDirectory* pt = raw_l1_table(i, j, k);
|
||||
|
||||
for (u64 l = 0; l < 512; l++)
|
||||
{
|
||||
PageTableEntry& l1 = pt->entries[l];
|
||||
if (!l1.present) continue;
|
||||
|
||||
// FIXME: Maybe we shouldn't delete some pages in an address space, such as shared memory.
|
||||
TRY(MemoryManager::free_frame(l1.get_address()));
|
||||
}
|
||||
|
||||
TRY(MemoryManager::free_frame(l2.get_address()));
|
||||
}
|
||||
|
||||
TRY(MemoryManager::free_frame(l3.get_address()));
|
||||
}
|
||||
|
||||
TRY(MemoryManager::free_frame(l4.get_address()));
|
||||
}
|
||||
|
||||
// No need to clean up manually, the ScopeGuard we set up earlier will do that for us.
|
||||
return {};
|
||||
}
|
||||
|
||||
PageDirectory* kernel_page_directory()
|
||||
{
|
||||
return g_kernel_directory;
|
||||
|
Loading…
Reference in New Issue
Block a user