MMU: unmap and remap for x86_64

This commit is contained in:
apio 2022-11-13 16:51:21 +01:00
parent ba1bf72e1b
commit ae235e5538
3 changed files with 92 additions and 23 deletions

View File

@ -26,7 +26,7 @@ namespace MMU
void flush_all();
Result<PageDirectory*> create_page_directory();
Result<PageDirectory*> create_page_directory_for_userspace();
void setup_initial_page_directory();
size_t page_size();

View File

@ -160,6 +160,39 @@ namespace MMU
return result;
}
Result<PageTableEntry*> find_entry(u64 virt)
{
auto& l4 = l4_entry(virt);
if (!l4.present) return err;
auto& l3 = l3_entry(virt);
if (!l3.present) return err;
if (l3.larger_pages) return &l3;
auto& l2 = l2_entry(virt);
if (!l2.present) return err;
if (l2.larger_pages) return &l2;
return &l1_entry(virt);
}
Result<PageTableEntry*> apply_cascading_flags(u64 virt, int flags)
{
auto& l4 = l4_entry(virt);
if (!l4.present) return err;
if (flags & Flags::ReadWrite) l4.read_write = true;
if (flags & Flags::User) l4.user = true;
auto& l3 = l3_entry(virt);
if (!l3.present) return err;
if (l3.larger_pages) return &l3;
if (flags & Flags::ReadWrite) l3.read_write = true;
if (flags & Flags::User) l3.user = true;
auto& l2 = l2_entry(virt);
if (!l2.present) return err;
if (l2.larger_pages) return &l2;
if (flags & Flags::ReadWrite) l2.read_write = true;
if (flags & Flags::User) l2.user = true;
auto& l1 = l1_entry(virt);
return &l1;
}
Result<void> map(u64 virt, u64 phys, int flags)
{
auto& l4 = l4_entry(virt);
@ -214,37 +247,50 @@ namespace MMU
if (flags & Flags::WriteThrough) l1.write_through = true;
if (flags & Flags::CacheDisable) l1.cache_disabled = true;
if (flags & Flags::NoExecute) l1.no_execute = true;
if (l1.ignore0 || l1.ignore1) return {1};
l1.set_address(phys);
return {};
}
Result<void> remap(u64 virt, int flags)
{
auto rc = apply_cascading_flags(virt, flags);
if (rc.has_error()) return rc.release_error();
auto& l1 = *rc.release_value();
if (!l1.present) return err;
if (flags & Flags::ReadWrite) l1.read_write = true;
if (flags & Flags::User) l1.user = true;
if (flags & Flags::WriteThrough) l1.write_through = true;
if (flags & Flags::CacheDisable) l1.cache_disabled = true;
if (flags & Flags::NoExecute) l1.no_execute = true;
return {};
}
Result<u64> unmap(u64 virt)
{
auto rc = find_entry(virt);
if (rc.has_error()) return rc.release_error();
auto& l1 = *rc.release_value();
if (!l1.present) return err;
u64 address = l1.get_address();
memset(&l1, 0, sizeof(l1));
flush_page(virt);
return address;
}
Result<u64> get_physical(u64 virt)
{
auto& l4 = l4_entry(virt);
if (!l4.present) return err;
auto& l3 = l3_entry(virt);
if (!l3.present) return err;
if (l3.larger_pages) return l3.get_address();
auto& l2 = l2_entry(virt);
if (!l2.present) return err;
if (l2.larger_pages) return l2.get_address();
auto& l1 = l1_entry(virt);
auto rc = find_entry(virt);
if (rc.has_error()) return rc.release_error();
auto& l1 = *rc.release_value();
if (!l1.present) return err;
return l1.get_address();
}
Result<int> get_flags(u64 virt)
{
auto& l4 = l4_entry(virt);
if (!l4.present) return err;
auto& l3 = l3_entry(virt);
if (!l3.present) return err;
if (l3.larger_pages) return arch_flags_to_mmu(l3);
auto& l2 = l2_entry(virt);
if (!l2.present) return err;
if (l2.larger_pages) return arch_flags_to_mmu(l2);
auto& l1 = l1_entry(virt);
auto rc = find_entry(virt);
if (rc.has_error()) return rc.release_error();
auto& l1 = *rc.release_value();
if (!l1.present) return err;
return arch_flags_to_mmu(l1);
}

View File

@ -6,6 +6,12 @@
extern u8 fb[1];
void hang()
{
for (;;)
;
}
extern "C" void _start()
{
Init::check_magic();
@ -31,14 +37,14 @@ extern "C" void _start()
else
{
Serial::println("Failed to map page");
goto failure;
hang();
}
if (MMU::get_physical(address).release_value() == physical) Serial::println("Mapping is active ;)");
else
{
Serial::println("Mapping is not active");
goto failure;
hang();
}
flags = MMU::get_flags(address).release_value();
@ -52,7 +58,24 @@ extern "C" void _start()
Serial::println("Can write to pointer");
failure:
auto urc = MMU::unmap(address);
if (urc.has_error())
{
Serial::println("Failed to unmap page");
hang();
}
if (urc.release_value() != physical)
{
Serial::println("unmap returned a different address than the one we mapped");
hang();
}
Serial::println("Unmapped memory, writing to it should crash");
*ptr = 16;
Serial::println("ERROR: we should have crashed by this point");
for (;;)
;