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();
|
void flush_all();
|
||||||
|
|
||||||
Result<PageDirectory*> create_page_directory();
|
Result<PageDirectory*> create_page_directory_for_userspace();
|
||||||
void setup_initial_page_directory();
|
void setup_initial_page_directory();
|
||||||
|
|
||||||
size_t page_size();
|
size_t page_size();
|
||||||
|
@ -160,6 +160,39 @@ namespace MMU
|
|||||||
return result;
|
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)
|
Result<void> map(u64 virt, u64 phys, int flags)
|
||||||
{
|
{
|
||||||
auto& l4 = l4_entry(virt);
|
auto& l4 = l4_entry(virt);
|
||||||
@ -214,37 +247,50 @@ namespace MMU
|
|||||||
if (flags & Flags::WriteThrough) l1.write_through = true;
|
if (flags & Flags::WriteThrough) l1.write_through = true;
|
||||||
if (flags & Flags::CacheDisable) l1.cache_disabled = true;
|
if (flags & Flags::CacheDisable) l1.cache_disabled = true;
|
||||||
if (flags & Flags::NoExecute) l1.no_execute = true;
|
if (flags & Flags::NoExecute) l1.no_execute = true;
|
||||||
if (l1.ignore0 || l1.ignore1) return {1};
|
|
||||||
l1.set_address(phys);
|
l1.set_address(phys);
|
||||||
return {};
|
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)
|
Result<u64> get_physical(u64 virt)
|
||||||
{
|
{
|
||||||
auto& l4 = l4_entry(virt);
|
auto rc = find_entry(virt);
|
||||||
if (!l4.present) return err;
|
if (rc.has_error()) return rc.release_error();
|
||||||
auto& l3 = l3_entry(virt);
|
auto& l1 = *rc.release_value();
|
||||||
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);
|
|
||||||
if (!l1.present) return err;
|
if (!l1.present) return err;
|
||||||
return l1.get_address();
|
return l1.get_address();
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<int> get_flags(u64 virt)
|
Result<int> get_flags(u64 virt)
|
||||||
{
|
{
|
||||||
auto& l4 = l4_entry(virt);
|
auto rc = find_entry(virt);
|
||||||
if (!l4.present) return err;
|
if (rc.has_error()) return rc.release_error();
|
||||||
auto& l3 = l3_entry(virt);
|
auto& l1 = *rc.release_value();
|
||||||
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);
|
|
||||||
if (!l1.present) return err;
|
if (!l1.present) return err;
|
||||||
return arch_flags_to_mmu(l1);
|
return arch_flags_to_mmu(l1);
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,12 @@
|
|||||||
|
|
||||||
extern u8 fb[1];
|
extern u8 fb[1];
|
||||||
|
|
||||||
|
void hang()
|
||||||
|
{
|
||||||
|
for (;;)
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
extern "C" void _start()
|
extern "C" void _start()
|
||||||
{
|
{
|
||||||
Init::check_magic();
|
Init::check_magic();
|
||||||
@ -31,14 +37,14 @@ extern "C" void _start()
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
Serial::println("Failed to map page");
|
Serial::println("Failed to map page");
|
||||||
goto failure;
|
hang();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (MMU::get_physical(address).release_value() == physical) Serial::println("Mapping is active ;)");
|
if (MMU::get_physical(address).release_value() == physical) Serial::println("Mapping is active ;)");
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Serial::println("Mapping is not active");
|
Serial::println("Mapping is not active");
|
||||||
goto failure;
|
hang();
|
||||||
}
|
}
|
||||||
|
|
||||||
flags = MMU::get_flags(address).release_value();
|
flags = MMU::get_flags(address).release_value();
|
||||||
@ -52,7 +58,24 @@ extern "C" void _start()
|
|||||||
|
|
||||||
Serial::println("Can write to pointer");
|
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 (;;)
|
for (;;)
|
||||||
;
|
;
|
||||||
|
Loading…
Reference in New Issue
Block a user