aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFelix Morgner <felix.morgner@ost.ch>2025-12-10 21:55:42 +0100
committerFelix Morgner <felix.morgner@ost.ch>2025-12-10 21:55:42 +0100
commiteafbf588760c289b7f54a4771b39af0ccfe8cf59 (patch)
treefabf14d8c908a187b0f3247eecac349a56d99b2d
parentf0c5ac3c8222d4d89b8e2d2a726427a7ec64e538 (diff)
downloadteachos-eafbf588760c289b7f54a4771b39af0ccfe8cf59.tar.xz
teachos-eafbf588760c289b7f54a4771b39af0ccfe8cf59.zip
kapi: extract page_mapper interface
-rw-r--r--arch/x86_64/CMakeLists.txt1
-rw-r--r--arch/x86_64/include/x86_64/memory/kernel_mapper.hpp5
-rw-r--r--arch/x86_64/include/x86_64/memory/page_table.hpp65
-rw-r--r--arch/x86_64/include/x86_64/memory/paging_root.hpp9
-rw-r--r--arch/x86_64/include/x86_64/memory/recursive_page_mapper.hpp23
-rw-r--r--arch/x86_64/include/x86_64/memory/scoped_mapping.hpp9
-rw-r--r--arch/x86_64/src/kapi/memory.cpp29
-rw-r--r--arch/x86_64/src/memory/kernel_mapper.cpp7
-rw-r--r--arch/x86_64/src/memory/paging_root.cpp52
-rw-r--r--arch/x86_64/src/memory/recursive_page_mapper.cpp38
-rw-r--r--arch/x86_64/src/memory/scoped_mapping.cpp99
-rw-r--r--kapi/CMakeLists.txt1
-rw-r--r--kapi/include/kapi/memory.hpp2
-rw-r--r--kapi/include/kapi/memory/page_mapper.hpp82
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