diff --git a/kernel/src/arch/MMU.h b/kernel/src/arch/MMU.h index 5f6fac42..624427f6 100644 --- a/kernel/src/arch/MMU.h +++ b/kernel/src/arch/MMU.h @@ -26,7 +26,7 @@ namespace MMU void flush_all(); - Result create_page_directory(); + Result create_page_directory_for_userspace(); void setup_initial_page_directory(); size_t page_size(); diff --git a/kernel/src/arch/x86_64/MMU.cpp b/kernel/src/arch/x86_64/MMU.cpp index b6533bfa..ff6e9534 100644 --- a/kernel/src/arch/x86_64/MMU.cpp +++ b/kernel/src/arch/x86_64/MMU.cpp @@ -160,6 +160,39 @@ namespace MMU return result; } + Result 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 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 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 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 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 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 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); } diff --git a/kernel/src/main.cpp b/kernel/src/main.cpp index 4d47e607..fa03a90c 100644 --- a/kernel/src/main.cpp +++ b/kernel/src/main.cpp @@ -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 (;;) ;