aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFelix Morgner <felix.morgner@ost.ch>2026-04-01 11:12:20 +0200
committerFelix Morgner <felix.morgner@ost.ch>2026-04-01 11:12:20 +0200
commit419f4bebff5745b46bf30092dc7a7ca43449ea2e (patch)
tree4b509ca6da26eeadaec193440c936954e4367f4e
parentc30ba8bc8c1cf80a7e9b46e9f1a66dc1b409fcbd (diff)
downloadteachos-419f4bebff5745b46bf30092dc7a7ca43449ea2e.tar.xz
teachos-419f4bebff5745b46bf30092dc7a7ca43449ea2e.zip
kernel/tests: implement basic simulated memory
-rw-r--r--kernel/kapi/memory.cpp8
-rw-r--r--kernel/tests/CMakeLists.txt14
-rw-r--r--kernel/tests/include/kernel/tests/simulated_memory.hpp19
-rw-r--r--kernel/tests/kapi/memory.cpp77
-rw-r--r--kernel/tests/src/main.cpp4
-rw-r--r--kernel/tests/src/simulated_memory.cpp33
6 files changed, 150 insertions, 5 deletions
diff --git a/kernel/kapi/memory.cpp b/kernel/kapi/memory.cpp
index 2803d76..06a3165 100644
--- a/kernel/kapi/memory.cpp
+++ b/kernel/kapi/memory.cpp
@@ -125,14 +125,18 @@ namespace kapi::memory
}
auto const flags = page_mapper::flags::writable | page_mapper::flags::supervisor_only | page_mapper::flags::global;
+ auto bitmap_ptr = static_cast<std::uint64_t *>(nullptr);
std::ranges::for_each(std::views::iota(0uz, bitmap_pages), [&](auto index) {
auto page = page::containing(pmm_metadata_base + index * page::size);
auto frame = memory::frame(bitmap_frames->first.number() + index);
- active_page_mapper->map(page, frame, flags);
+ auto mapped = active_page_mapper->map(page, frame, flags);
+ if (!bitmap_ptr)
+ {
+ bitmap_ptr = reinterpret_cast<std::uint64_t *>(mapped);
+ }
});
- auto bitmap_ptr = static_cast<std::uint64_t *>(pmm_metadata_base);
auto bitmap =
std::span{bitmap_ptr, (bitmap_bytes + kstd::type_size<std::uint64_t> - 1_B) / kstd::type_size<std::uint64_t>};
diff --git a/kernel/tests/CMakeLists.txt b/kernel/tests/CMakeLists.txt
index 0e2ea36..0855520 100644
--- a/kernel/tests/CMakeLists.txt
+++ b/kernel/tests/CMakeLists.txt
@@ -7,9 +7,19 @@ add_library("kernel_test_support"
"kapi/cpu.cpp"
"kapi/interrupts.cpp"
"kapi/memory.cpp"
-
+
"src/log_buffer.cpp"
"src/main.cpp"
+ "src/simulated_memory.cpp"
+)
+
+file(GLOB_RECURSE KERNEL_TEST_SUPPORT_HEADERS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "include/**.hpp")
+
+target_sources("kernel_test_support" PUBLIC
+ FILE_SET HEADERS
+ BASE_DIRS "include"
+ FILES
+ ${KERNEL_TEST_SUPPORT_HEADERS}
)
target_include_directories("kernel_test_support" PUBLIC
@@ -18,6 +28,7 @@ target_include_directories("kernel_test_support" PUBLIC
target_link_libraries("kernel_test_support" PUBLIC
"os::kapi"
+ "os::kernel"
"Catch2::Catch2"
)
@@ -37,7 +48,6 @@ target_include_directories("kernel_tests" PRIVATE
target_link_libraries("kernel_tests" PRIVATE
"os::kernel_test_support"
- "os::kernel"
"libs::kstd"
)
diff --git a/kernel/tests/include/kernel/tests/simulated_memory.hpp b/kernel/tests/include/kernel/tests/simulated_memory.hpp
new file mode 100644
index 0000000..156b1e1
--- /dev/null
+++ b/kernel/tests/include/kernel/tests/simulated_memory.hpp
@@ -0,0 +1,19 @@
+#ifndef TEACHOS_KERNEL_TESTS_SIMULATED_MEMORY_HPP
+#define TEACHOS_KERNEL_TESTS_SIMULATED_MEMORY_HPP
+
+#include <kstd/units>
+
+#include <cstddef>
+
+namespace kernel::tests::simulated_memory
+{
+
+ auto init(kstd::units::bytes size) -> void;
+
+ auto pmm_metadata_base() -> std::byte *;
+
+ auto ram_base() -> std::byte *;
+
+} // namespace kernel::tests::simulated_memory
+
+#endif \ No newline at end of file
diff --git a/kernel/tests/kapi/memory.cpp b/kernel/tests/kapi/memory.cpp
index 4482c74..6de2f60 100644
--- a/kernel/tests/kapi/memory.cpp
+++ b/kernel/tests/kapi/memory.cpp
@@ -1,11 +1,86 @@
+#include "kapi/memory.hpp"
+
#include <kapi/memory.hpp>
+#include "kernel/tests/simulated_memory.hpp"
+
+#include <kstd/print>
+#include <kstd/units>
+
+#include <cstddef>
+#include <cstdint>
+#include <optional>
+#include <utility>
+
namespace kapi::memory
{
+ namespace
+ {
+ //! The size of the simulated RAM.
+ constexpr auto simulate_memory_size = kstd::units::MiB(32);
+
+ struct test_boostrap_frame_allocator : frame_allocator
+ {
+ auto mark_used(frame) -> void override {}
+
+ auto allocate_many(std::size_t count) noexcept -> std::optional<std::pair<frame, std::size_t>> override
+ {
+ auto start = next_free_frame;
+ next_free_frame += count;
+ return std::pair{frame{start}, count};
+ }
+
+ auto release_many(std::pair<frame, std::size_t>) -> void override {}
+
+ std::size_t next_free_frame{};
+ } boostrap_allocator;
+
+ struct test_page_mapper : page_mapper
+ {
+ auto map(page page, frame frame, flags flags) -> std::byte * override
+ {
+ kstd::println("mapping page {} onto frame {} with flags {}", page.number(), frame.number(),
+ static_cast<std::uint64_t>(flags));
+
+ if ((page.start_address() & pmm_metadata_base.raw()) == pmm_metadata_base.raw())
+ {
+ auto offset = page.start_address() & ~pmm_metadata_base.raw();
+ return kernel::tests::simulated_memory::pmm_metadata_base() + offset;
+ }
+
+ return nullptr;
+ }
+
+ auto unmap(page page) -> void override
+ {
+ kstd::println("unmapping page {}", page.number());
+ }
+
+ auto try_unmap(page page) noexcept -> bool override
+ {
+ kstd::println("trying to unmap page {}", page.number());
+ return false;
+ }
+ } test_mapper;
+
+ auto handoff_to_kernel_pmm(frame_allocator & new_allocator) -> void
+ {
+ for (auto i = 0uz; i < boostrap_allocator.next_free_frame; ++i)
+ {
+ new_allocator.mark_used(frame{i});
+ }
+ }
+
+ } // namespace
+
auto init() -> void
{
- // TODO: initialize simulated memory.
+ kernel::tests::simulated_memory::init(simulate_memory_size);
+ set_frame_allocator(boostrap_allocator);
+ set_page_mapper(test_mapper);
+
+ init_pmm(simulate_memory_size / frame::size, handoff_to_kernel_pmm);
}
} // namespace kapi::memory \ No newline at end of file
diff --git a/kernel/tests/src/main.cpp b/kernel/tests/src/main.cpp
index c0ec12f..69fd633 100644
--- a/kernel/tests/src/main.cpp
+++ b/kernel/tests/src/main.cpp
@@ -12,6 +12,10 @@ auto main(int argc, char ** argv) -> int
kapi::interrupts::enable();
kapi::memory::init();
+ // note: no kernel heap is created, since we are in the test environment. Nonetheless, we still initialize the memory
+ // subsystem, so that components that rely on it can be tested. No component must ever rely on the heap allocator
+ // directly, rather they have to go through the new and delete. However, some components may use the frame allocator
+ // and page mapper in order to perform their tasks.
return Catch::Session().run(argc, argv);
}
diff --git a/kernel/tests/src/simulated_memory.cpp b/kernel/tests/src/simulated_memory.cpp
new file mode 100644
index 0000000..9a9b354
--- /dev/null
+++ b/kernel/tests/src/simulated_memory.cpp
@@ -0,0 +1,33 @@
+#include "kernel/tests/simulated_memory.hpp"
+
+#include <kstd/units>
+
+#include <cstddef>
+#include <vector>
+
+namespace kernel::tests::simulated_memory
+{
+
+ namespace
+ {
+ auto constinit ram_storage = std::vector<std::byte>{};
+ auto constinit pmm_storage = std::vector<std::byte>{};
+ } // namespace
+
+ auto init(kstd::units::bytes size) -> void
+ {
+ ram_storage.resize(size / kstd::units::bytes{1});
+ pmm_storage.resize(size / kstd::units::bytes{1});
+ }
+
+ auto pmm_metadata_base() -> std::byte *
+ {
+ return pmm_storage.data();
+ }
+
+ auto ram_base() -> std::byte *
+ {
+ return ram_storage.data();
+ }
+
+} // namespace kernel::tests::simulated_memory \ No newline at end of file