aboutsummaryrefslogtreecommitdiff
path: root/kernel/src/test_support/page_mapper.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/src/test_support/page_mapper.cpp')
-rw-r--r--kernel/src/test_support/page_mapper.cpp78
1 files changed, 78 insertions, 0 deletions
diff --git a/kernel/src/test_support/page_mapper.cpp b/kernel/src/test_support/page_mapper.cpp
new file mode 100644
index 0000000..abdcae5
--- /dev/null
+++ b/kernel/src/test_support/page_mapper.cpp
@@ -0,0 +1,78 @@
+#include "kernel/test_support/page_mapper.hpp"
+
+#include "kapi/memory.hpp"
+
+#include <kstd/units>
+
+#include <cstddef>
+#include <format>
+#include <stdexcept>
+#include <sys/mman.h>
+
+namespace kernel::tests
+{
+
+ page_mapper::page_mapper(kstd::units::bytes memory_size)
+ : memory{memory_size}
+ {}
+
+ auto page_mapper::map(kapi::memory::page page, kapi::memory::frame frame, flags) -> std::byte *
+ {
+ auto result = page_mappings.insert({page.number(), frame});
+ if (!result.second)
+ {
+ auto error = std::format("Page {} was already mapped!", page.number());
+ throw std::invalid_argument{error};
+ }
+
+ auto page_address = page.start_address();
+ auto sandbox_start = memory.heap_base();
+ auto sandbox_end = sandbox_start + memory.heap_size();
+
+ if (page_address >= sandbox_start && page_address < sandbox_end)
+ {
+ auto virtual_target = static_cast<std::byte *>(page_address);
+ auto physical_offset = frame.number() * kapi::memory::frame::size;
+ auto mapped_ptr = mmap(virtual_target, kapi::memory::page::size.value, PROT_READ | PROT_WRITE,
+ MAP_SHARED | MAP_FIXED, memory.memory_descriptor(), physical_offset.value);
+ if (mapped_ptr == MAP_FAILED)
+ {
+ throw std::runtime_error("Failed to map page");
+ }
+
+ return static_cast<std::byte *>(mapped_ptr);
+ }
+ else if (page_address >= kapi::memory::mmio_base)
+ {
+ throw std::runtime_error("MMIO mapping not yet supported in testing!");
+ }
+ else if (page_address >= kapi::memory::higher_half_direct_map_base)
+ {
+ auto offset = frame.number() * kapi::memory::frame::size;
+ return memory.ram_base() + offset;
+ }
+
+ return nullptr;
+ }
+
+ auto page_mapper::unmap(kapi::memory::page page) -> void
+ {
+ if (!try_unmap(page))
+ {
+ auto error = std::format("Page {} was never mapped!", page.number());
+ throw std::invalid_argument{error};
+ }
+ }
+
+ auto page_mapper::try_unmap(kapi::memory::page page) noexcept -> bool
+ {
+ if (page_mappings.contains(page.number()))
+ {
+ page_mappings.erase(page.number());
+ return true;
+ }
+
+ return false;
+ }
+
+} // namespace kernel::tests \ No newline at end of file