MMU: unmap and remap for x86_64
This commit is contained in:
parent
ba1bf72e1b
commit
ae235e5538
@ -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();
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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 (;;)
|
||||
;
|
||||
|
Loading…
Reference in New Issue
Block a user