diff options
Diffstat (limited to 'arch/x86_64/src/memory/paging_root.cpp')
| -rw-r--r-- | arch/x86_64/src/memory/paging_root.cpp | 55 |
1 files changed, 54 insertions, 1 deletions
diff --git a/arch/x86_64/src/memory/paging_root.cpp b/arch/x86_64/src/memory/paging_root.cpp index 6b8e1ab..5ca2bf0 100644 --- a/arch/x86_64/src/memory/paging_root.cpp +++ b/arch/x86_64/src/memory/paging_root.cpp @@ -1,10 +1,15 @@ #include "x86_64/memory/paging_root.hpp" #include "kapi/memory.hpp" +#include "kapi/system.hpp" +#include "x86_64/memory/page_table.hpp" #include "x86_64/memory/page_utilities.hpp" +#include "x86_64/memory/scoped_mapping.hpp" +#include <cstddef> #include <cstdint> +#include <memory> #include <optional> namespace teachos::memory::x86_64 @@ -13,7 +18,45 @@ namespace teachos::memory::x86_64 namespace { constexpr auto PML_RECURSIVE_BASE = std::uintptr_t{0177777'776'776'776'776'0000uz}; - } + + //! Perform the actual mapping of the page, via the recursive page map. + //! + //! On any level above PML1, the entries need to not be no_execute, because the image is densely packed. The entries + //! also need to be writable, since the mapping is being performed through the recursive page map hierarchy. When + //! setting the final entry in the PML1, the actually desired flags are set as is, with the present bit added, thus + //! still enforcing non-writability and non-execution of the affected page. + template<std::size_t Level> + requires(Level > 1uz && Level < 5uz) + auto do_map(recursive_page_table<Level> * pml, page page, page_table::entry::flags flags, + frame_allocator & allocator) + { + auto index = pml_index<Level>(page); + flags = flags & ~page_table::entry::flags::no_execute; + flags = flags | page_table::entry::flags::writable; + if (!(*pml)[index].present()) + { + auto new_table_frame = allocator.allocate(); + auto mapping = scoped_mapping{page, allocator}; + (*pml)[index].frame(new_table_frame.value(), page_table::entry::flags::present | flags); + auto new_table = std::optional{std::construct_at(*pml->next(index))}; + return new_table; + } + (*pml)[index] |= flags; + return pml->next(index); + } + + //! Perform the actual PML1 update. + auto do_map(page_table * pml, page page, frame frame, page_table::entry::flags flags) -> std::optional<std::byte *> + { + auto index = pml_index<1>(page); + if ((*pml)[index].present()) + { + system::panic("[x86_64:MEM] Tried to map a page that is already mapped"); + } + (*pml)[index].frame(frame, page_table::entry::flags::present | flags); + return std::optional{static_cast<std::byte *>(page.start_address())}; + } + } // namespace auto paging_root::get() -> paging_root & { @@ -71,4 +114,14 @@ namespace teachos::memory::x86_64 .or_else(handle_huge_page); } + auto paging_root::map(page page, frame frame, page_table::entry::flags flags, frame_allocator & allocator) + -> std::optional<std::byte *> + { + return std::optional{this} + .and_then([&](auto pml) -> auto { return do_map(pml, page, flags, allocator); }) + .and_then([&](auto pml) -> auto { return do_map(pml, page, flags, allocator); }) + .and_then([&](auto pml) -> auto { return do_map(pml, page, flags, allocator); }) + .and_then([&](auto pml) -> auto { return do_map(pml, page, frame, flags); }); + } + } // namespace teachos::memory::x86_64
\ No newline at end of file |
