diff options
| author | Felix Morgner <felix.morgner@ost.ch> | 2025-12-10 21:55:42 +0100 |
|---|---|---|
| committer | Felix Morgner <felix.morgner@ost.ch> | 2025-12-10 21:55:42 +0100 |
| commit | eafbf588760c289b7f54a4771b39af0ccfe8cf59 (patch) | |
| tree | fabf14d8c908a187b0f3247eecac349a56d99b2d | |
| parent | f0c5ac3c8222d4d89b8e2d2a726427a7ec64e538 (diff) | |
| download | teachos-eafbf588760c289b7f54a4771b39af0ccfe8cf59.tar.xz teachos-eafbf588760c289b7f54a4771b39af0ccfe8cf59.zip | |
kapi: extract page_mapper interface
| -rw-r--r-- | arch/x86_64/CMakeLists.txt | 1 | ||||
| -rw-r--r-- | arch/x86_64/include/x86_64/memory/kernel_mapper.hpp | 5 | ||||
| -rw-r--r-- | arch/x86_64/include/x86_64/memory/page_table.hpp | 65 | ||||
| -rw-r--r-- | arch/x86_64/include/x86_64/memory/paging_root.hpp | 9 | ||||
| -rw-r--r-- | arch/x86_64/include/x86_64/memory/recursive_page_mapper.hpp | 23 | ||||
| -rw-r--r-- | arch/x86_64/include/x86_64/memory/scoped_mapping.hpp | 9 | ||||
| -rw-r--r-- | arch/x86_64/src/kapi/memory.cpp | 29 | ||||
| -rw-r--r-- | arch/x86_64/src/memory/kernel_mapper.cpp | 7 | ||||
| -rw-r--r-- | arch/x86_64/src/memory/paging_root.cpp | 52 | ||||
| -rw-r--r-- | arch/x86_64/src/memory/recursive_page_mapper.cpp | 38 | ||||
| -rw-r--r-- | arch/x86_64/src/memory/scoped_mapping.cpp | 99 | ||||
| -rw-r--r-- | kapi/CMakeLists.txt | 1 | ||||
| -rw-r--r-- | kapi/include/kapi/memory.hpp | 2 | ||||
| -rw-r--r-- | kapi/include/kapi/memory/page_mapper.hpp | 82 |
14 files changed, 300 insertions, 122 deletions
diff --git a/arch/x86_64/CMakeLists.txt b/arch/x86_64/CMakeLists.txt index 0b9009c..7bd8d07 100644 --- a/arch/x86_64/CMakeLists.txt +++ b/arch/x86_64/CMakeLists.txt @@ -27,6 +27,7 @@ target_sources("x86_64" PRIVATE "src/memory/mmu.cpp" "src/memory/page_table.cpp" "src/memory/paging_root.cpp" + "src/memory/recursive_page_mapper.cpp" "src/memory/region_allocator.cpp" "src/memory/scoped_mapping.cpp" diff --git a/arch/x86_64/include/x86_64/memory/kernel_mapper.hpp b/arch/x86_64/include/x86_64/memory/kernel_mapper.hpp index 4b681ae..1f217ae 100644 --- a/arch/x86_64/include/x86_64/memory/kernel_mapper.hpp +++ b/arch/x86_64/include/x86_64/memory/kernel_mapper.hpp @@ -1,8 +1,6 @@ #ifndef TEACHOS_X86_64_KERNEL_MAPPER_HPP #define TEACHOS_X86_64_KERNEL_MAPPER_HPP -#include "kapi/memory.hpp" - #include <elf/format.hpp> #include <elf/section_header.hpp> #include <multiboot2/information.hpp> @@ -16,14 +14,13 @@ namespace teachos::memory::x86_64 { using section_header_type = elf::section_header<elf::format::elf64>; - kernel_mapper(frame_allocator & allocator, multiboot2::information_view const * mbi); + explicit kernel_mapper(multiboot2::information_view const * mbi); auto remap_kernel() -> void; private: auto map_section(section_header_type const & section, std::string_view name) -> void; - frame_allocator * m_allocator; multiboot2::information_view const * m_mbi; std::uintptr_t m_kernel_load_base; }; diff --git a/arch/x86_64/include/x86_64/memory/page_table.hpp b/arch/x86_64/include/x86_64/memory/page_table.hpp index 22616e8..6a9c045 100644 --- a/arch/x86_64/include/x86_64/memory/page_table.hpp +++ b/arch/x86_64/include/x86_64/memory/page_table.hpp @@ -146,4 +146,69 @@ namespace kstd::ext }; } // namespace kstd::ext +namespace teachos::memory::x86_64 +{ + + constexpr auto to_mapper_flags(page_table::entry::flags flags) -> page_mapper::flags + { + using table_flags = page_table::entry::flags; + using mapper_flags = page_mapper::flags; + + auto result = mapper_flags{}; + + if ((flags & table_flags::no_execute) == table_flags::empty) + { + result |= mapper_flags::executable; + } + + if ((flags & table_flags::writable) != table_flags::empty) + { + result |= mapper_flags::writable; + } + + if ((flags & table_flags::disable_cache) != table_flags::empty) + { + result |= mapper_flags::uncached; + } + + if ((flags & table_flags::user_accessible) == table_flags::empty) + { + result |= mapper_flags::supervisor; + } + + return result; + } + + constexpr auto to_table_flags(page_mapper::flags flags) -> page_table::entry::flags + { + using table_flags = page_table::entry::flags; + using mapper_flags = page_mapper::flags; + + auto result = table_flags{}; + + if ((flags & mapper_flags::executable) == mapper_flags::empty) + { + result |= table_flags::no_execute; + } + + if ((flags & mapper_flags::writable) != mapper_flags::empty) + { + result |= table_flags::writable; + } + + if ((flags & mapper_flags::uncached) != mapper_flags::empty) + { + result |= table_flags::disable_cache; + } + + if ((flags & mapper_flags::supervisor) != mapper_flags::empty) + { + result |= table_flags::user_accessible; + } + + return result; + } + +} // namespace teachos::memory::x86_64 + #endif
\ No newline at end of file diff --git a/arch/x86_64/include/x86_64/memory/paging_root.hpp b/arch/x86_64/include/x86_64/memory/paging_root.hpp index d4aa023..ed95106 100644 --- a/arch/x86_64/include/x86_64/memory/paging_root.hpp +++ b/arch/x86_64/include/x86_64/memory/paging_root.hpp @@ -30,8 +30,13 @@ namespace teachos::memory::x86_64 //! @param page A page to map. //! @param frame The frame into which to map the page. //! @param flags The flags to apply to the mapping. - //! @param allocator The frame allocator used to allocate any required page tables. - auto map(page page, frame frame, entry::flags flags, frame_allocator & allocator) -> std::optional<std::byte *>; + auto map(page page, frame frame, entry::flags flags) -> std::optional<std::byte *>; + + //! Unmap the given page from virtual memory. + //! + //! @warning If the page has not previously been mapped, this function will panic. + //! @param page The page to unmap + auto unmap(page) -> void; private: paging_root() = default; diff --git a/arch/x86_64/include/x86_64/memory/recursive_page_mapper.hpp b/arch/x86_64/include/x86_64/memory/recursive_page_mapper.hpp new file mode 100644 index 0000000..a66c8d1 --- /dev/null +++ b/arch/x86_64/include/x86_64/memory/recursive_page_mapper.hpp @@ -0,0 +1,23 @@ +#ifndef TEACHOS_X86_64_RECURSIVE_PAGE_MAPPER_HPP +#define TEACHOS_X86_64_RECURSIVE_PAGE_MAPPER_HPP + +#include "kapi/memory.hpp" + +namespace teachos::memory::x86_64 +{ + + struct recursive_page_mapper : page_mapper + { + explicit recursive_page_mapper(frame_allocator & allocator); + + auto map(page page, frame frame, flags flags) -> std::byte * override; + auto unmap(page page) -> void override; + auto try_unmap(page page) -> bool override; + + private: + frame_allocator * m_allocator; + }; + +} // namespace teachos::memory::x86_64 + +#endif
\ No newline at end of file diff --git a/arch/x86_64/include/x86_64/memory/scoped_mapping.hpp b/arch/x86_64/include/x86_64/memory/scoped_mapping.hpp index d4844fb..415ea8e 100644 --- a/arch/x86_64/include/x86_64/memory/scoped_mapping.hpp +++ b/arch/x86_64/include/x86_64/memory/scoped_mapping.hpp @@ -22,8 +22,7 @@ namespace teachos::memory::x86_64 //! Construct a new scoped mapping, which can be used to map a frame to the given unused page. //! @param page An unused page. If the page is already mapped, this constructor will panic. - //! @param allocator An allocator to be used to allocate any page maps required to map the frame. - scoped_mapping(page page, frame_allocator & allocator); + explicit scoped_mapping(page page); //! Unmap the mapped frame if one was mapped. //! @note Any page tables that were allocated to support the mapping will be released. @@ -53,17 +52,13 @@ namespace teachos::memory::x86_64 //! @note If no frame was ever mapped, this function will panic. auto unmap() -> void; - auto swap(scoped_mapping & other) -> void; + friend auto swap(scoped_mapping & lhs, scoped_mapping & rhs) -> void; private: page m_page; - frame_allocator * m_allocator; bool m_mapped; - std::uint8_t m_allocated; }; - auto swap(scoped_mapping & lhs, scoped_mapping & rhs) -> void; - } // namespace teachos::memory::x86_64 #endif
\ No newline at end of file diff --git a/arch/x86_64/src/kapi/memory.cpp b/arch/x86_64/src/kapi/memory.cpp index ed3edef..00b9de3 100644 --- a/arch/x86_64/src/kapi/memory.cpp +++ b/arch/x86_64/src/kapi/memory.cpp @@ -13,6 +13,7 @@ #include "x86_64/memory/page_table.hpp" #include "x86_64/memory/page_utilities.hpp" #include "x86_64/memory/paging_root.hpp" +#include "x86_64/memory/recursive_page_mapper.hpp" #include "x86_64/memory/region_allocator.hpp" #include "x86_64/memory/scoped_mapping.hpp" @@ -29,6 +30,8 @@ namespace teachos::memory { // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) auto constinit allocator = static_cast<frame_allocator *>(nullptr); + // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) + auto constinit mapper = static_cast<page_mapper *>(nullptr); constexpr auto static unused_page_address = linear_address{0x0000'7fff'cafe'faceuz}; constexpr auto static recursive_page_map_index = x86_64::page_table::entry_count - 2; @@ -70,7 +73,7 @@ namespace teachos::memory auto page = page::containing(unused_page_address); - auto temporary_mapper = scoped_mapping{page, allocator}; + auto temporary_mapper = scoped_mapping{page}; auto new_pml4_frame = allocator.allocate(); auto pml4 = std::construct_at(temporary_mapper.map_as<page_table>(*new_pml4_frame, entry_flags::writable)); @@ -124,6 +127,15 @@ namespace teachos::memory return *allocator; } + auto active_mapper() -> page_mapper & + { + if (!mapper) + { + system::panic("[x86_64] The page mapper has not been set you."); + } + return *mapper; + } + auto init() -> void { auto static constinit is_initialized = std::atomic_flag{}; @@ -132,14 +144,19 @@ namespace teachos::memory system::panic("[x86_64] Memory management has already been initialized."); } - auto allocator = create_early_frame_allocator(); enable_cpu_protections(); - auto allocation_buffer = x86_64::buffered_allocator<4>{&allocator}; + auto early_allocator = create_early_frame_allocator(); + auto allocation_buffer = x86_64::buffered_allocator<4>{&early_allocator}; + allocator = &allocation_buffer; + + auto recursive_mapper = x86_64::recursive_page_mapper{allocation_buffer}; + mapper = &recursive_mapper; + auto new_pml4_frame = inject_faux_pml4(allocation_buffer); - auto mapper = x86_64::kernel_mapper{allocation_buffer, boot::bootstrap_information.mbi}; - mapper.remap_kernel(); + auto kernel_mapper = x86_64::kernel_mapper{boot::bootstrap_information.mbi}; + kernel_mapper.remap_kernel(); cio::println("[x86_64:MEM] prepared new kernel image page maps."); auto cr3 = cpu::x86_64::cr3::read(); @@ -149,6 +166,8 @@ namespace teachos::memory // remap_heap(heap::KERNEL_HEAP_START, heap::KERNEL_HEAP_SIZE); // video::vga::text::write("Heap remapping successful", video::vga::text::common_attributes::green_on_black); // video::vga::text::newline(); + mapper = nullptr; + allocator = nullptr; } } // namespace teachos::memory diff --git a/arch/x86_64/src/memory/kernel_mapper.cpp b/arch/x86_64/src/memory/kernel_mapper.cpp index b1d12a4..f46b5b5 100644 --- a/arch/x86_64/src/memory/kernel_mapper.cpp +++ b/arch/x86_64/src/memory/kernel_mapper.cpp @@ -32,9 +32,8 @@ namespace teachos::memory::x86_64 } // namespace - kernel_mapper::kernel_mapper(frame_allocator & allocator, multiboot2::information_view const * mbi) - : m_allocator{&allocator} - , m_mbi(std::move(mbi)) + kernel_mapper::kernel_mapper(multiboot2::information_view const * mbi) + : m_mbi{std::move(mbi)} , m_kernel_load_base{std::bit_cast<std::uintptr_t>(&boot::x86_64::TEACHOS_VMA)} {} @@ -100,7 +99,7 @@ namespace teachos::memory::x86_64 for (auto i = 0uz; i < number_of_pages; ++i) { - paging_root::get().map(page{first_page.number() + i}, frame{first_frame.number() + i}, page_flags, *m_allocator); + paging_root::get().map(page{first_page.number() + i}, frame{first_frame.number() + i}, page_flags); } } diff --git a/arch/x86_64/src/memory/paging_root.cpp b/arch/x86_64/src/memory/paging_root.cpp index 5ca2bf0..c458093 100644 --- a/arch/x86_64/src/memory/paging_root.cpp +++ b/arch/x86_64/src/memory/paging_root.cpp @@ -27,16 +27,15 @@ namespace teachos::memory::x86_64 //! 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 do_map(recursive_page_table<Level> * pml, page page, page_table::entry::flags flags) { 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}; + auto new_table_frame = active_allocator().allocate(); + auto mapping = scoped_mapping{page}; (*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; @@ -114,14 +113,49 @@ 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 *> + auto paging_root::map(page page, frame frame, page_table::entry::flags flags) -> 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, flags); }) + .and_then([&](auto pml) -> auto { return do_map(pml, page, flags); }) + .and_then([&](auto pml) -> auto { return do_map(pml, page, flags); }) .and_then([&](auto pml) -> auto { return do_map(pml, page, frame, flags); }); } + auto paging_root::unmap(page page) -> void + { + if (!this->translate(page)) + { + system::panic("[x86_64:MEM] Tried to unmap a page that was not mapped."); + } + + auto pml4 = this; + auto pml3 = pml4->next(pml_index<4>(page)).value(); + auto pml2 = pml3->next(pml_index<3>(page)).value(); + auto pml1 = pml2->next(pml_index<2>(page)).value(); + + (*pml1)[pml_index<1>(page)].clear(); + + if (pml1->empty()) + { + auto pml1_frame = (*pml2)[pml_index<2>(page)].frame().value(); + active_allocator().release(pml1_frame); + (*pml2)[pml_index<2>(page)].clear(); + } + + if (pml2->empty()) + { + auto pml2_frame = (*pml3)[pml_index<3>(page)].frame().value(); + active_allocator().release(pml2_frame); + (*pml3)[pml_index<3>(page)].clear(); + } + + if (pml3->empty()) + { + auto pml3_frame = (*pml4)[pml_index<4>(page)].frame().value(); + active_allocator().release(pml3_frame); + (*pml4)[pml_index<4>(page)].clear(); + } + } + } // namespace teachos::memory::x86_64
\ No newline at end of file diff --git a/arch/x86_64/src/memory/recursive_page_mapper.cpp b/arch/x86_64/src/memory/recursive_page_mapper.cpp new file mode 100644 index 0000000..ea89f38 --- /dev/null +++ b/arch/x86_64/src/memory/recursive_page_mapper.cpp @@ -0,0 +1,38 @@ +#include "x86_64/memory/recursive_page_mapper.hpp" + +#include "kapi/system.hpp" + +#include "x86_64/memory/page_table.hpp" +#include "x86_64/memory/paging_root.hpp" + +namespace teachos::memory::x86_64 +{ + recursive_page_mapper::recursive_page_mapper(frame_allocator & allocator) + : m_allocator{&allocator} + {} + + auto recursive_page_mapper::map(page page, frame frame, flags flags) -> std::byte * + { + return paging_root::get().map(page, frame, to_table_flags(flags)).value_or(nullptr); + } + + auto recursive_page_mapper::unmap(page page) -> void + { + if (!try_unmap(page)) + { + system::panic("[x86_64:MEM] Tried to unmap a page that was not mapped."); + } + } + + auto recursive_page_mapper::try_unmap(page page) -> bool + { + auto & root = paging_root::get(); + if (!root.translate(page)) + { + return false; + } + root.unmap(page); + return true; + } + +} // namespace teachos::memory::x86_64
\ No newline at end of file diff --git a/arch/x86_64/src/memory/scoped_mapping.cpp b/arch/x86_64/src/memory/scoped_mapping.cpp index 44dbf45..6f3461c 100644 --- a/arch/x86_64/src/memory/scoped_mapping.cpp +++ b/arch/x86_64/src/memory/scoped_mapping.cpp @@ -5,10 +5,8 @@ #include "x86_64/memory/mmu.hpp" #include "x86_64/memory/page_table.hpp" -#include "x86_64/memory/page_utilities.hpp" #include "x86_64/memory/paging_root.hpp" -#include <memory> #include <utility> namespace teachos::memory::x86_64 @@ -16,16 +14,12 @@ namespace teachos::memory::x86_64 scoped_mapping::scoped_mapping(scoped_mapping && other) noexcept : m_page{std::exchange(other.m_page, page{})} - , m_allocator{std::exchange(other.m_allocator, nullptr)} , m_mapped{std::exchange(other.m_mapped, false)} - , m_allocated{std::exchange(other.m_allocated, 0)} {} - scoped_mapping::scoped_mapping(page page, frame_allocator & allocator) + scoped_mapping::scoped_mapping(page page) : m_page{page} - , m_allocator{&allocator} , m_mapped{false} - , m_allocated{} { if (paging_root::get().translate(page)) { @@ -44,105 +38,28 @@ namespace teachos::memory::x86_64 auto scoped_mapping::operator=(scoped_mapping && other) noexcept -> scoped_mapping & { - this->swap(other); + swap(*this, other); return *this; } auto scoped_mapping::map(frame frame, page_table::entry::flags flags) -> std::byte * { - auto & pml4 = paging_root::get(); - auto pml4_index = pml_index<4>(m_page); - if (!pml4[pml4_index].present()) - { - auto new_frame = m_allocator->allocate(); - pml4[pml4_index].frame(*new_frame, page_table::entry::flags::present | flags); - std::construct_at(pml4.next(pml4_index).value()); - m_allocated |= 1uz << 2; - } - - auto pml3 = pml4.next(pml4_index).value(); - auto pml3_index = pml_index<3>(m_page); - if (!(*pml3)[pml3_index].present()) - { - auto new_frame = m_allocator->allocate(); - (*pml3)[pml3_index].frame(*new_frame, page_table::entry::flags::present | flags); - std::construct_at((*pml3).next(pml3_index).value()); - m_allocated |= 1uz << 1; - } - - auto pml2 = (*pml3).next(pml3_index).value(); - auto pml2_index = pml_index<2>(m_page); - if (!(*pml2)[pml2_index].present()) - { - auto new_frame = m_allocator->allocate(); - (*pml2)[pml2_index].frame(*new_frame, page_table::entry::flags::present | flags); - std::construct_at((*pml2).next(pml2_index).value()); - m_allocated |= 1uz << 0; - } - - auto pml1 = (*pml2).next(pml2_index).value(); - auto pml1_index = pml_index<1>(m_page); - (*pml1)[pml1_index].frame(frame, page_table::entry::flags::present | flags); - + auto result = active_mapper().map(m_page, frame, to_mapper_flags(flags)); m_mapped = true; - - return static_cast<std::byte *>(m_page.start_address()); + return result; } auto scoped_mapping::unmap() -> void { - if (!m_mapped) - { - system::panic("[MEM] Tried to release an unmapped temporary mapping!"); - } - - auto pml4 = &paging_root::get(); - auto pml3 = pml4->next(pml_index<4>(m_page)).value(); - auto pml2 = pml3->next(pml_index<3>(m_page)).value(); - auto pml1 = pml2->next(pml_index<2>(m_page)).value(); - - (*pml1)[pml_index<1>(m_page)].clear(); - - if (m_allocated & 1uz << 0) - { - auto pml1_frame = (*pml2)[pml_index<2>(m_page)].frame().value(); - m_allocator->release(pml1_frame); - (*pml2)[pml_index<2>(m_page)].clear(); - } - - if (m_allocated & 1uz << 1) - { - auto pml2_frame = (*pml3)[pml_index<3>(m_page)].frame().value(); - m_allocator->release(pml2_frame); - (*pml3)[pml_index<3>(m_page)].clear(); - } - - if (m_allocated & 1uz << 2) - { - auto pml3_frame = (*pml4)[pml_index<4>(m_page)].frame().value(); - m_allocator->release(pml3_frame); - (*pml4)[pml_index<4>(m_page)].clear(); - } - + active_mapper().unmap(m_page); m_mapped = false; } - auto scoped_mapping::swap(scoped_mapping & other) -> void - { - using std::swap; - - if (&other == this) - return; - - swap(m_page, other.m_page); - swap(m_allocator, other.m_allocator); - swap(m_mapped, other.m_mapped); - swap(m_allocated, other.m_allocated); - } - auto swap(scoped_mapping & lhs, scoped_mapping & rhs) -> void { - lhs.swap(rhs); + using std::swap; + swap(lhs.m_page, rhs.m_page); + swap(lhs.m_mapped, rhs.m_mapped); } } // namespace teachos::memory::x86_64
\ No newline at end of file diff --git a/kapi/CMakeLists.txt b/kapi/CMakeLists.txt index ca26615..d0ecb70 100644 --- a/kapi/CMakeLists.txt +++ b/kapi/CMakeLists.txt @@ -11,6 +11,7 @@ target_sources("kapi" PUBLIC "include/kapi/memory/address.hpp" "include/kapi/memory/frame_allocator.hpp" "include/kapi/memory/frame.hpp" + "include/kapi/memory/page_mapper.hpp" "include/kapi/memory/page.hpp" "include/kapi/system.hpp" ) diff --git a/kapi/include/kapi/memory.hpp b/kapi/include/kapi/memory.hpp index 4279274..9ca1267 100644 --- a/kapi/include/kapi/memory.hpp +++ b/kapi/include/kapi/memory.hpp @@ -5,10 +5,12 @@ #include "kapi/memory/frame.hpp" // IWYU pragma: export #include "kapi/memory/frame_allocator.hpp" // IWYU pragma: export #include "kapi/memory/page.hpp" // IWYU pragma: export +#include "kapi/memory/page_mapper.hpp" // IWYU pragma: export namespace teachos::memory { auto active_allocator() -> frame_allocator &; + auto active_mapper() -> page_mapper &; auto init() -> void; } // namespace teachos::memory diff --git a/kapi/include/kapi/memory/page_mapper.hpp b/kapi/include/kapi/memory/page_mapper.hpp new file mode 100644 index 0000000..aa5cf76 --- /dev/null +++ b/kapi/include/kapi/memory/page_mapper.hpp @@ -0,0 +1,82 @@ +#ifndef TEACHOS_KAPI_MEMORY_PAGE_MAPPER_HPP +#define TEACHOS_KAPI_MEMORY_PAGE_MAPPER_HPP + +// IWYU pragma: private, include "kapi/memory.hpp" + +#include "kapi/memory/frame.hpp" +#include "kapi/memory/page.hpp" + +#include <kstd/ext/bitfield_enum> + +#include <type_traits> + +namespace teachos::memory +{ + + // NOLINTNEXTLINE(cppcoreguidelines-special-member-functions) + struct page_mapper + { + enum struct flags : std::uint64_t + { + empty, + writable = 1 << 0, + executable = 1 << 1, + uncached = 1 << 2, + supervisor = 1 << 3, + }; + + virtual ~page_mapper() = default; + + /** + * Map a page into a given frame, applying the given flags. + * + * @param page The page to map. + * @param frame The frame to map the page into. + * @param flags The flags to map the page with. + * @return A pointer to the first byte of mapped page. + */ + virtual auto map(page page, frame frame, flags flags) -> std::byte * = 0; + + /** + * Unmap the given page. + * + * @warning If the provided page is not mapped, this function will panic. + * @param page The page to unmap. + */ + virtual auto unmap(page page) -> void = 0; + + /** + * Try to unmap the given page. + * + * @param page The page to unmap + * @return true iff. the page was successfully unmapped, false otherwise. + */ + virtual auto try_unmap(page page) -> bool = 0; + + /** + * Map a page into a given frame, applyint the given flags. + * + * @tparam T The type of data contained in the page. + * @param page The page to map. + * @param frame The frame to map the page into. + * @param flags The flags to map the page with. + * @return A pointer to the first T in the page. + */ + template<typename T> + [[nodiscard]] auto map_as(page page, frame frame, flags flags) -> T * + { + return std::bit_cast<T *>(map(page, frame, flags)); + } + }; + +} // namespace teachos::memory + +namespace kstd::ext +{ + template<> + struct is_bitfield_enum<teachos::memory::page_mapper::flags> : std::true_type + { + }; +} // namespace kstd::ext + +#endif
\ No newline at end of file |
