aboutsummaryrefslogtreecommitdiff
path: root/arch/x86_64/src/memory/paging_root.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86_64/src/memory/paging_root.cpp')
-rw-r--r--arch/x86_64/src/memory/paging_root.cpp55
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