From cd70186845c90aaaefbdb21b6d0f3c7caaa90a27 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Wed, 1 Apr 2026 08:01:28 +0200 Subject: kernel: split off objects into a library --- kernel/CMakeLists.txt | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) (limited to 'kernel') diff --git a/kernel/CMakeLists.txt b/kernel/CMakeLists.txt index cb3d8a5..206923e 100644 --- a/kernel/CMakeLists.txt +++ b/kernel/CMakeLists.txt @@ -1,4 +1,4 @@ -add_executable("kernel" +add_library("kernel-objs" OBJECT # Platform-independent KAPI implementation "kapi/boot_modules.cpp" "kapi/cio.cpp" @@ -40,13 +40,29 @@ add_executable("kernel" "src/filesystem/vfs.cpp" ) -target_include_directories("kernel" PRIVATE +target_include_directories("kernel-objs" PUBLIC "include" ) +target_link_libraries("kernel-objs" PRIVATE + "os::kapi" +) + +file(GLOB_RECURSE KERNEL_HEADERS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "include/**.hpp") + +target_sources("kernel-objs" PUBLIC + FILE_SET HEADERS + BASE_DIRS "include" + FILES + ${KERNEL_HEADERS} +) + +add_executable("kernel" + $ +) + target_link_libraries("kernel" PRIVATE "os::arch" - "os::kapi" ) target_link_options("kernel" PRIVATE @@ -61,15 +77,6 @@ set_property(TARGET "kernel" "${KERNEL_LINKER_SCRIPT}" ) -file(GLOB_RECURSE KERNEL_HEADERS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "include/**.hpp") - -target_sources("kernel" PUBLIC - FILE_SET HEADERS - BASE_DIRS "include" - FILES - ${KERNEL_HEADERS} -) - target_disassemble("kernel") target_extract_debug_symbols("kernel") target_strip("kernel") -- cgit v1.2.3 From 9b80bd2ca528a376c2bb6831020b3d78e4b252d6 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Wed, 1 Apr 2026 08:10:10 +0200 Subject: build: fix kernel+arch build --- kernel/CMakeLists.txt | 49 +++++++++++++++++++++++++++---------------------- 1 file changed, 27 insertions(+), 22 deletions(-) (limited to 'kernel') diff --git a/kernel/CMakeLists.txt b/kernel/CMakeLists.txt index 206923e..4aa72e1 100644 --- a/kernel/CMakeLists.txt +++ b/kernel/CMakeLists.txt @@ -12,7 +12,6 @@ add_library("kernel-objs" OBJECT "kstd/print.cpp" # Kernel Implementation - "src/main.cpp" "src/memory/bitmap_allocator.cpp" "src/memory/block_list_allocator.cpp" "src/memory/operators.cpp" @@ -44,7 +43,7 @@ target_include_directories("kernel-objs" PUBLIC "include" ) -target_link_libraries("kernel-objs" PRIVATE +target_link_libraries("kernel-objs" PUBLIC "os::kapi" ) @@ -57,28 +56,34 @@ target_sources("kernel-objs" PUBLIC ${KERNEL_HEADERS} ) -add_executable("kernel" - $ -) +add_library("os::kernel" ALIAS "kernel-objs") -target_link_libraries("kernel" PRIVATE - "os::arch" -) +if(CMAKE_CROSSCOMPILING) + add_executable("kernel" + "src/main.cpp" + ) -target_link_options("kernel" PRIVATE - "-T${KERNEL_LINKER_SCRIPT}" - "-no-pie" - "-nostdlib" -) + target_link_libraries("kernel" PRIVATE + "os::arch" + "os::kernel" + ) -set_property(TARGET "kernel" - APPEND - PROPERTY LINK_DEPENDS - "${KERNEL_LINKER_SCRIPT}" -) + target_link_options("kernel" PRIVATE + "-T${KERNEL_LINKER_SCRIPT}" + "-no-pie" + "-nostdlib" + ) + + set_property(TARGET "kernel" + APPEND + PROPERTY LINK_DEPENDS + "${KERNEL_LINKER_SCRIPT}" + ) + + target_disassemble("kernel") + target_extract_debug_symbols("kernel") + target_strip("kernel") -target_disassemble("kernel") -target_extract_debug_symbols("kernel") -target_strip("kernel") + target_generate_bootable_iso("kernel") +endif() -target_generate_bootable_iso("kernel") -- cgit v1.2.3 From 5ae03c52fe33882416aa6044993d8422ccb33ab4 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Wed, 1 Apr 2026 08:49:21 +0200 Subject: kernel: begin basic bht implementation --- kernel/CMakeLists.txt | 15 ++++++---- kernel/tests/CMakeLists.txt | 49 +++++++++++++++++++++++++++++++ kernel/tests/include/kernel/tests/cpu.hpp | 18 ++++++++++++ kernel/tests/kapi/cpu.cpp | 13 ++++++++ kernel/tests/src/main.cpp | 6 ++++ kernel/tests/src/test_support.cpp | 19 ++++++++++++ 6 files changed, 114 insertions(+), 6 deletions(-) create mode 100644 kernel/tests/CMakeLists.txt create mode 100644 kernel/tests/include/kernel/tests/cpu.hpp create mode 100644 kernel/tests/kapi/cpu.cpp create mode 100644 kernel/tests/src/main.cpp create mode 100644 kernel/tests/src/test_support.cpp (limited to 'kernel') diff --git a/kernel/CMakeLists.txt b/kernel/CMakeLists.txt index 4aa72e1..854fb33 100644 --- a/kernel/CMakeLists.txt +++ b/kernel/CMakeLists.txt @@ -1,4 +1,4 @@ -add_library("kernel-objs" OBJECT +add_library("kernel_objs" OBJECT # Platform-independent KAPI implementation "kapi/boot_modules.cpp" "kapi/cio.cpp" @@ -14,7 +14,6 @@ add_library("kernel-objs" OBJECT # Kernel Implementation "src/memory/bitmap_allocator.cpp" "src/memory/block_list_allocator.cpp" - "src/memory/operators.cpp" "src/memory.cpp" "src/devices/block_device.cpp" "src/devices/block_device_utils.cpp" @@ -39,28 +38,29 @@ add_library("kernel-objs" OBJECT "src/filesystem/vfs.cpp" ) -target_include_directories("kernel-objs" PUBLIC +target_include_directories("kernel_objs" PUBLIC "include" ) -target_link_libraries("kernel-objs" PUBLIC +target_link_libraries("kernel_objs" PUBLIC "os::kapi" ) file(GLOB_RECURSE KERNEL_HEADERS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "include/**.hpp") -target_sources("kernel-objs" PUBLIC +target_sources("kernel_objs" PUBLIC FILE_SET HEADERS BASE_DIRS "include" FILES ${KERNEL_HEADERS} ) -add_library("os::kernel" ALIAS "kernel-objs") +add_library("os::kernel" ALIAS "kernel_objs") if(CMAKE_CROSSCOMPILING) add_executable("kernel" "src/main.cpp" + "src/memory/operators.cpp" ) target_link_libraries("kernel" PRIVATE @@ -85,5 +85,8 @@ if(CMAKE_CROSSCOMPILING) target_strip("kernel") target_generate_bootable_iso("kernel") +else() + enable_coverage("kernel_objs") + add_subdirectory("tests") endif() diff --git a/kernel/tests/CMakeLists.txt b/kernel/tests/CMakeLists.txt new file mode 100644 index 0000000..96053f1 --- /dev/null +++ b/kernel/tests/CMakeLists.txt @@ -0,0 +1,49 @@ +#[============================================================================[ +# Kernel Test Support (Fakes, Stubs, Mocks, etc.) +#]============================================================================] + +add_library("kernel_test_support" + "kapi/cpu.cpp" +) + +target_include_directories("kernel_test_support" PUBLIC + "include" +) + +target_link_libraries("kernel_test_support" PUBLIC + "os::kapi" +) + +add_library("os::kernel_test_support" ALIAS "kernel_test_support") + +#[============================================================================[ +# Kernel Tests +#]============================================================================] + +add_executable("kernel_tests" + "src/main.cpp" + "src/test_support.cpp" +) + +target_include_directories("kernel_tests" PRIVATE + "include" +) + +target_link_libraries("kernel_tests" PRIVATE + "os::kernel_test_support" + "os::kernel" + "libs::kstd" + "Catch2::Catch2" +) + +set_target_properties("kernel_tests" PROPERTIES + C_CLANG_TIDY "" + CXX_CLANG_TIDY "" + EXCLUDE_FROM_ALL NO +) + +enable_coverage("kernel_tests") + +add_executable("os::kernel_tests" ALIAS "kernel_tests") + +catch_discover_tests("os::kernel_tests") \ No newline at end of file diff --git a/kernel/tests/include/kernel/tests/cpu.hpp b/kernel/tests/include/kernel/tests/cpu.hpp new file mode 100644 index 0000000..81c0c6f --- /dev/null +++ b/kernel/tests/include/kernel/tests/cpu.hpp @@ -0,0 +1,18 @@ +#ifndef TEACHOS_KERNEL_TESTS_CPU_HPP +#define TEACHOS_KERNEL_TESTS_CPU_HPP + +#include + +namespace kernel::tests::cpu +{ + + struct halt : std::runtime_error + { + halt() + : std::runtime_error{"CPU halt requested!"} + {} + }; + +} // namespace kernel::tests::cpu + +#endif \ No newline at end of file diff --git a/kernel/tests/kapi/cpu.cpp b/kernel/tests/kapi/cpu.cpp new file mode 100644 index 0000000..f03fca0 --- /dev/null +++ b/kernel/tests/kapi/cpu.cpp @@ -0,0 +1,13 @@ +#include "kernel/tests/cpu.hpp" + +#include + +namespace kapi::cpu +{ + + auto halt() -> void + { + throw kernel::tests::cpu::halt{}; + } + +} // namespace kapi::cpu \ No newline at end of file diff --git a/kernel/tests/src/main.cpp b/kernel/tests/src/main.cpp new file mode 100644 index 0000000..89bb1c7 --- /dev/null +++ b/kernel/tests/src/main.cpp @@ -0,0 +1,6 @@ +#include + +auto main(int argc, char ** argv) -> int +{ + return Catch::Session().run(argc, argv); +} \ No newline at end of file diff --git a/kernel/tests/src/test_support.cpp b/kernel/tests/src/test_support.cpp new file mode 100644 index 0000000..bbf5dc0 --- /dev/null +++ b/kernel/tests/src/test_support.cpp @@ -0,0 +1,19 @@ +#include "kapi/cpu.hpp" + +#include "kernel/tests/cpu.hpp" + +#include + +SCENARIO("Kernel test support infrastructure", "[support]") +{ + GIVEN("the test support infrastructure is initialized") + { + WHEN("when a CPU halt is requested") + { + THEN("the correct exception is thrown") + { + REQUIRE_THROWS_AS(kapi::cpu::halt(), kernel::tests::cpu::halt); + } + } + } +} \ No newline at end of file -- cgit v1.2.3 From fa1ea53e6f3dd6b9b5f5f8160776b230184a30bf Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Wed, 1 Apr 2026 09:36:31 +0200 Subject: kernel/tests: implement platform CIO kapi --- kernel/tests/CMakeLists.txt | 5 ++- kernel/tests/include/kernel/tests/log_buffer.hpp | 32 +++++++++++++++ kernel/tests/kapi/cio.cpp | 38 ++++++++++++++++++ kernel/tests/src/log_buffer.cpp | 39 ++++++++++++++++++ kernel/tests/src/main.cpp | 4 ++ kernel/tests/src/test_support.cpp | 19 --------- kernel/tests/src/test_support.tests.cpp | 51 ++++++++++++++++++++++++ 7 files changed, 168 insertions(+), 20 deletions(-) create mode 100644 kernel/tests/include/kernel/tests/log_buffer.hpp create mode 100644 kernel/tests/kapi/cio.cpp create mode 100644 kernel/tests/src/log_buffer.cpp delete mode 100644 kernel/tests/src/test_support.cpp create mode 100644 kernel/tests/src/test_support.tests.cpp (limited to 'kernel') diff --git a/kernel/tests/CMakeLists.txt b/kernel/tests/CMakeLists.txt index 96053f1..39ab3b7 100644 --- a/kernel/tests/CMakeLists.txt +++ b/kernel/tests/CMakeLists.txt @@ -3,6 +3,7 @@ #]============================================================================] add_library("kernel_test_support" + "kapi/cio.cpp" "kapi/cpu.cpp" ) @@ -21,8 +22,10 @@ add_library("os::kernel_test_support" ALIAS "kernel_test_support") #]============================================================================] add_executable("kernel_tests" + "src/log_buffer.cpp" "src/main.cpp" - "src/test_support.cpp" + + "src/test_support.tests.cpp" ) target_include_directories("kernel_tests" PRIVATE diff --git a/kernel/tests/include/kernel/tests/log_buffer.hpp b/kernel/tests/include/kernel/tests/log_buffer.hpp new file mode 100644 index 0000000..5f2a1a7 --- /dev/null +++ b/kernel/tests/include/kernel/tests/log_buffer.hpp @@ -0,0 +1,32 @@ +#ifndef KERNEL_TESTS_LOG_BUFFER_HPP +#define KERNEL_TESTS_LOG_BUFFER_HPP + +#include +#include + +namespace kernel::tests::log_buffer +{ + + //! Append a message to the testing log buffer. + //! + //! @param message The message to append. + auto append(std::string const & message) -> void; + + //! Clear the testing log buffer. + auto clear() -> void; + + //! Get the testing log buffer as a single string. + //! + //! @return The testing log buffer as a single string. + auto flat_messages() -> std::string; + + //! Get the testing log buffer. + //! + //! @note Messages may be split across multiple entries if they are longer than the internal kernel print buffer size. + //! + //! @return The testing log buffer. + auto messages() -> std::vector const &; + +} // namespace kernel::tests::log_buffer + +#endif \ No newline at end of file diff --git a/kernel/tests/kapi/cio.cpp b/kernel/tests/kapi/cio.cpp new file mode 100644 index 0000000..6359fa8 --- /dev/null +++ b/kernel/tests/kapi/cio.cpp @@ -0,0 +1,38 @@ +#include + +#include "kernel/tests/log_buffer.hpp" + +#include +#include +#include + +namespace kapi::cio +{ + + namespace + { + + class test_output_device : public output_device + { + public: + test_output_device() = default; + + auto write(output_stream stream, std::string_view text) -> void override + { + auto & standard_stream = stream == output_stream::stdout ? std::cout : std::cerr; + standard_stream << text; + if (text != "\n") + { + kernel::tests::log_buffer::append(std::string{text}); + } + } + } device{}; + + } // namespace + + auto init() -> void + { + set_output_device(device); + } + +} // namespace kapi::cio \ No newline at end of file diff --git a/kernel/tests/src/log_buffer.cpp b/kernel/tests/src/log_buffer.cpp new file mode 100644 index 0000000..9e30afb --- /dev/null +++ b/kernel/tests/src/log_buffer.cpp @@ -0,0 +1,39 @@ +#include "kernel/tests/log_buffer.hpp" + +#include +#include +#include + +namespace kernel::tests::log_buffer +{ + + namespace + { + std::vector recorded_messages{}; + } + + auto append(std::string const & message) -> void + { + recorded_messages.push_back(message); + } + + auto clear() -> void + { + recorded_messages.clear(); + } + + auto flat_messages() -> std::string + { + return std::ranges::fold_left(recorded_messages, std::string{}, + [](std::string accumulator, std::string const & message) { + accumulator += message; + return accumulator; + }); + } + + auto messages() -> std::vector const & + { + return recorded_messages; + } + +} // namespace kernel::tests::log_buffer diff --git a/kernel/tests/src/main.cpp b/kernel/tests/src/main.cpp index 89bb1c7..f1f9bb4 100644 --- a/kernel/tests/src/main.cpp +++ b/kernel/tests/src/main.cpp @@ -1,6 +1,10 @@ +#include + #include auto main(int argc, char ** argv) -> int { + kapi::cio::init(); + return Catch::Session().run(argc, argv); } \ No newline at end of file diff --git a/kernel/tests/src/test_support.cpp b/kernel/tests/src/test_support.cpp deleted file mode 100644 index bbf5dc0..0000000 --- a/kernel/tests/src/test_support.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "kapi/cpu.hpp" - -#include "kernel/tests/cpu.hpp" - -#include - -SCENARIO("Kernel test support infrastructure", "[support]") -{ - GIVEN("the test support infrastructure is initialized") - { - WHEN("when a CPU halt is requested") - { - THEN("the correct exception is thrown") - { - REQUIRE_THROWS_AS(kapi::cpu::halt(), kernel::tests::cpu::halt); - } - } - } -} \ No newline at end of file diff --git a/kernel/tests/src/test_support.tests.cpp b/kernel/tests/src/test_support.tests.cpp new file mode 100644 index 0000000..f835e65 --- /dev/null +++ b/kernel/tests/src/test_support.tests.cpp @@ -0,0 +1,51 @@ +#include "kapi/cpu.hpp" +#include "kapi/system.hpp" + +#include "kernel/tests/cpu.hpp" +#include "kernel/tests/log_buffer.hpp" + +#include + +#include + +SCENARIO("Kernel test support infrastructure", "[support]") +{ + GIVEN("the test support infrastructure is initialized") + { + WHEN("a CPU halt is requested") + { + THEN("the correct exception is thrown") + { + REQUIRE_THROWS_AS(kapi::cpu::halt(), kernel::tests::cpu::halt); + } + } + + WHEN("a the system panics") + { + kernel::tests::log_buffer::clear(); + + THEN("the correct exception is thrown") + { + REQUIRE_THROWS_AS(kapi::system::panic("[kernel:tests] Test Panic"), kernel::tests::cpu::halt); + } + + THEN("the message is appended to the log buffer") + { + CHECK_THROWS(kapi::system::panic("[kernel:tests] Test Panic")); + REQUIRE(kernel::tests::log_buffer::flat_messages().contains("[kernel:tests] Test Panic")); + } + } + + WHEN("a regular print is issued") + { + kernel::tests::log_buffer::clear(); + + kstd::println("[kernel:tests] Test Print"); + + THEN("the message is appended to the log buffer") + { + REQUIRE(kernel::tests::log_buffer::flat_messages().contains("[kernel:tests] Test Print")); + } + } + } +} \ No newline at end of file -- cgit v1.2.3 From 0b139b3c66b340bb560dc608ea3b15a07ec95ee3 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Wed, 1 Apr 2026 09:48:12 +0200 Subject: kernel/tests: add kapi::cpu::init stub --- kernel/tests/kapi/cpu.cpp | 16 ++++++++++++++++ kernel/tests/src/main.cpp | 4 +++- 2 files changed, 19 insertions(+), 1 deletion(-) (limited to 'kernel') diff --git a/kernel/tests/kapi/cpu.cpp b/kernel/tests/kapi/cpu.cpp index f03fca0..3ecaadc 100644 --- a/kernel/tests/kapi/cpu.cpp +++ b/kernel/tests/kapi/cpu.cpp @@ -2,9 +2,25 @@ #include +#include +#include + namespace kapi::cpu { + auto init() -> void + { + auto static initialized = std::atomic_flag{}; + if (initialized.test_and_set()) + { + throw std::logic_error("kapi::cpu::init() called more than once"); + } + + // TODO: make sure that simulated interrupt can run. + + return; + } + auto halt() -> void { throw kernel::tests::cpu::halt{}; diff --git a/kernel/tests/src/main.cpp b/kernel/tests/src/main.cpp index f1f9bb4..a21aa9d 100644 --- a/kernel/tests/src/main.cpp +++ b/kernel/tests/src/main.cpp @@ -1,10 +1,12 @@ #include +#include #include auto main(int argc, char ** argv) -> int { kapi::cio::init(); + kapi::cpu::init(); return Catch::Session().run(argc, argv); -} \ No newline at end of file +} -- cgit v1.2.3 From b4049de007f9d15c12db227e4745a559359a99e9 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Wed, 1 Apr 2026 09:51:42 +0200 Subject: kernel/tests: add kapi::interrupts::init stub --- kernel/tests/CMakeLists.txt | 9 +++++---- kernel/tests/kapi/interrupts.cpp | 11 +++++++++++ kernel/tests/src/main.cpp | 2 ++ 3 files changed, 18 insertions(+), 4 deletions(-) create mode 100644 kernel/tests/kapi/interrupts.cpp (limited to 'kernel') diff --git a/kernel/tests/CMakeLists.txt b/kernel/tests/CMakeLists.txt index 39ab3b7..2fe5ff3 100644 --- a/kernel/tests/CMakeLists.txt +++ b/kernel/tests/CMakeLists.txt @@ -5,6 +5,10 @@ add_library("kernel_test_support" "kapi/cio.cpp" "kapi/cpu.cpp" + "kapi/interrupts.cpp" + + "src/log_buffer.cpp" + "src/main.cpp" ) target_include_directories("kernel_test_support" PUBLIC @@ -13,6 +17,7 @@ target_include_directories("kernel_test_support" PUBLIC target_link_libraries("kernel_test_support" PUBLIC "os::kapi" + "Catch2::Catch2" ) add_library("os::kernel_test_support" ALIAS "kernel_test_support") @@ -22,9 +27,6 @@ add_library("os::kernel_test_support" ALIAS "kernel_test_support") #]============================================================================] add_executable("kernel_tests" - "src/log_buffer.cpp" - "src/main.cpp" - "src/test_support.tests.cpp" ) @@ -36,7 +38,6 @@ target_link_libraries("kernel_tests" PRIVATE "os::kernel_test_support" "os::kernel" "libs::kstd" - "Catch2::Catch2" ) set_target_properties("kernel_tests" PROPERTIES diff --git a/kernel/tests/kapi/interrupts.cpp b/kernel/tests/kapi/interrupts.cpp new file mode 100644 index 0000000..0077266 --- /dev/null +++ b/kernel/tests/kapi/interrupts.cpp @@ -0,0 +1,11 @@ +#include + +namespace kapi::interrupts +{ + + auto enable() -> void + { + // TODO: enable simulated interrupts. + } + +} // namespace kapi::interrupts \ No newline at end of file diff --git a/kernel/tests/src/main.cpp b/kernel/tests/src/main.cpp index a21aa9d..11e88a4 100644 --- a/kernel/tests/src/main.cpp +++ b/kernel/tests/src/main.cpp @@ -1,3 +1,4 @@ +#include "kapi/interrupts.hpp" #include #include @@ -7,6 +8,7 @@ auto main(int argc, char ** argv) -> int { kapi::cio::init(); kapi::cpu::init(); + kapi::interrupts::enable(); return Catch::Session().run(argc, argv); } -- cgit v1.2.3 From c30ba8bc8c1cf80a7e9b46e9f1a66dc1b409fcbd Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Wed, 1 Apr 2026 10:04:40 +0200 Subject: kernel/tests: add kapi::memory::init stub --- kernel/tests/CMakeLists.txt | 1 + kernel/tests/kapi/memory.cpp | 11 +++++++++++ kernel/tests/src/main.cpp | 3 +++ 3 files changed, 15 insertions(+) create mode 100644 kernel/tests/kapi/memory.cpp (limited to 'kernel') diff --git a/kernel/tests/CMakeLists.txt b/kernel/tests/CMakeLists.txt index 2fe5ff3..0e2ea36 100644 --- a/kernel/tests/CMakeLists.txt +++ b/kernel/tests/CMakeLists.txt @@ -6,6 +6,7 @@ add_library("kernel_test_support" "kapi/cio.cpp" "kapi/cpu.cpp" "kapi/interrupts.cpp" + "kapi/memory.cpp" "src/log_buffer.cpp" "src/main.cpp" diff --git a/kernel/tests/kapi/memory.cpp b/kernel/tests/kapi/memory.cpp new file mode 100644 index 0000000..4482c74 --- /dev/null +++ b/kernel/tests/kapi/memory.cpp @@ -0,0 +1,11 @@ +#include + +namespace kapi::memory +{ + + auto init() -> void + { + // TODO: initialize simulated memory. + } + +} // namespace kapi::memory \ No newline at end of file diff --git a/kernel/tests/src/main.cpp b/kernel/tests/src/main.cpp index 11e88a4..c0ec12f 100644 --- a/kernel/tests/src/main.cpp +++ b/kernel/tests/src/main.cpp @@ -1,4 +1,5 @@ #include "kapi/interrupts.hpp" +#include "kapi/memory.hpp" #include #include @@ -10,5 +11,7 @@ auto main(int argc, char ** argv) -> int kapi::cpu::init(); kapi::interrupts::enable(); + kapi::memory::init(); + return Catch::Session().run(argc, argv); } -- cgit v1.2.3 From 419f4bebff5745b46bf30092dc7a7ca43449ea2e Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Wed, 1 Apr 2026 11:12:20 +0200 Subject: kernel/tests: implement basic simulated memory --- kernel/kapi/memory.cpp | 8 ++- kernel/tests/CMakeLists.txt | 14 +++- .../include/kernel/tests/simulated_memory.hpp | 19 ++++++ kernel/tests/kapi/memory.cpp | 77 +++++++++++++++++++++- kernel/tests/src/main.cpp | 4 ++ kernel/tests/src/simulated_memory.cpp | 33 ++++++++++ 6 files changed, 150 insertions(+), 5 deletions(-) create mode 100644 kernel/tests/include/kernel/tests/simulated_memory.hpp create mode 100644 kernel/tests/src/simulated_memory.cpp (limited to 'kernel') 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(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(mapped); + } }); - auto bitmap_ptr = static_cast(pmm_metadata_base); auto bitmap = std::span{bitmap_ptr, (bitmap_bytes + kstd::type_size - 1_B) / kstd::type_size}; 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 + +#include + +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 +#include "kernel/tests/simulated_memory.hpp" + +#include +#include + +#include +#include +#include +#include + 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> override + { + auto start = next_free_frame; + next_free_frame += count; + return std::pair{frame{start}, count}; + } + + auto release_many(std::pair) -> 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(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 + +#include +#include + +namespace kernel::tests::simulated_memory +{ + + namespace + { + auto constinit ram_storage = std::vector{}; + auto constinit pmm_storage = std::vector{}; + } // 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 -- cgit v1.2.3 From 0369fb7c4baa543dfb36ebb39ab53ac7560994ba Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Wed, 1 Apr 2026 11:37:05 +0200 Subject: kernel/test: only initialize kernel when running tests --- kernel/tests/src/main.cpp | 35 ++++++++++++++++++++++++++--------- 1 file changed, 26 insertions(+), 9 deletions(-) (limited to 'kernel') diff --git a/kernel/tests/src/main.cpp b/kernel/tests/src/main.cpp index 69fd633..b3ae142 100644 --- a/kernel/tests/src/main.cpp +++ b/kernel/tests/src/main.cpp @@ -7,15 +7,32 @@ auto main(int argc, char ** argv) -> int { - kapi::cio::init(); - kapi::cpu::init(); - kapi::interrupts::enable(); + auto session = Catch::Session{}; - 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. + if (auto result = session.applyCommandLine(argc, argv); result != 0) + { + return result; + } - return Catch::Session().run(argc, argv); + auto const & config = session.configData(); + auto skip_init = config.listTests || // + config.listTags || // + config.listReporters || // + config.listListeners || // + config.showHelp; + + if (!skip_init) + { + kapi::cio::init(); + kapi::cpu::init(); + 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 session.run(); } -- cgit v1.2.3 From 1f652b8b5ca5dbea588975466801cb1479f3dda8 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Wed, 1 Apr 2026 12:15:25 +0200 Subject: kernel/tests: dissolve tests into source tree --- kernel/CMakeLists.txt | 42 ++++++++++- kernel/include/kernel/tests/cpu.hpp | 18 +++++ kernel/include/kernel/tests/log_buffer.hpp | 32 ++++++++ kernel/include/kernel/tests/simulated_memory.hpp | 19 +++++ kernel/kapi/cpu.tests.cpp | 19 +++++ kernel/kapi/system.tests.cpp | 30 ++++++++ kernel/kstd/print.tests.cpp | 23 ++++++ kernel/src/main.tests.cpp | 38 ++++++++++ kernel/src/test_support/kapi/cio.cpp | 38 ++++++++++ kernel/src/test_support/kapi/cpu.cpp | 29 ++++++++ kernel/src/test_support/kapi/interrupts.cpp | 11 +++ kernel/src/test_support/kapi/memory.cpp | 86 ++++++++++++++++++++++ kernel/src/test_support/log_buffer.cpp | 39 ++++++++++ kernel/src/test_support/simulated_memory.cpp | 33 +++++++++ kernel/tests/CMakeLists.txt | 64 ---------------- kernel/tests/include/kernel/tests/cpu.hpp | 18 ----- kernel/tests/include/kernel/tests/log_buffer.hpp | 32 -------- .../include/kernel/tests/simulated_memory.hpp | 19 ----- kernel/tests/kapi/cio.cpp | 38 ---------- kernel/tests/kapi/cpu.cpp | 29 -------- kernel/tests/kapi/interrupts.cpp | 11 --- kernel/tests/kapi/memory.cpp | 86 ---------------------- kernel/tests/src/log_buffer.cpp | 39 ---------- kernel/tests/src/main.cpp | 38 ---------- kernel/tests/src/simulated_memory.cpp | 33 --------- kernel/tests/src/test_support.tests.cpp | 51 ------------- 26 files changed, 456 insertions(+), 459 deletions(-) create mode 100644 kernel/include/kernel/tests/cpu.hpp create mode 100644 kernel/include/kernel/tests/log_buffer.hpp create mode 100644 kernel/include/kernel/tests/simulated_memory.hpp create mode 100644 kernel/kapi/cpu.tests.cpp create mode 100644 kernel/kapi/system.tests.cpp create mode 100644 kernel/kstd/print.tests.cpp create mode 100644 kernel/src/main.tests.cpp create mode 100644 kernel/src/test_support/kapi/cio.cpp create mode 100644 kernel/src/test_support/kapi/cpu.cpp create mode 100644 kernel/src/test_support/kapi/interrupts.cpp create mode 100644 kernel/src/test_support/kapi/memory.cpp create mode 100644 kernel/src/test_support/log_buffer.cpp create mode 100644 kernel/src/test_support/simulated_memory.cpp delete mode 100644 kernel/tests/CMakeLists.txt delete mode 100644 kernel/tests/include/kernel/tests/cpu.hpp delete mode 100644 kernel/tests/include/kernel/tests/log_buffer.hpp delete mode 100644 kernel/tests/include/kernel/tests/simulated_memory.hpp delete mode 100644 kernel/tests/kapi/cio.cpp delete mode 100644 kernel/tests/kapi/cpu.cpp delete mode 100644 kernel/tests/kapi/interrupts.cpp delete mode 100644 kernel/tests/kapi/memory.cpp delete mode 100644 kernel/tests/src/log_buffer.cpp delete mode 100644 kernel/tests/src/main.cpp delete mode 100644 kernel/tests/src/simulated_memory.cpp delete mode 100644 kernel/tests/src/test_support.tests.cpp (limited to 'kernel') diff --git a/kernel/CMakeLists.txt b/kernel/CMakeLists.txt index 854fb33..d6b3a1b 100644 --- a/kernel/CMakeLists.txt +++ b/kernel/CMakeLists.txt @@ -87,6 +87,46 @@ if(CMAKE_CROSSCOMPILING) target_generate_bootable_iso("kernel") else() enable_coverage("kernel_objs") - add_subdirectory("tests") + + add_library("kernel_test_support" + "src/test_support/kapi/cpu.cpp" + "src/test_support/kapi/cio.cpp" + "src/test_support/kapi/interrupts.cpp" + "src/test_support/kapi/memory.cpp" + "src/test_support/log_buffer.cpp" + "src/test_support/simulated_memory.cpp" + ) + add_library("os::kernel_test_support" ALIAS "kernel_test_support") + + target_link_libraries("kernel_test_support" PUBLIC + "os::kernel" + "Catch2::Catch2" + ) + + add_executable("kernel_tests" + # KAPI Shim Tests + "kapi/cpu.tests.cpp" + "kapi/system.tests.cpp" + + # KSTD Shim Tests + "kstd/print.tests.cpp" + + # Test Executable Main + "src/main.tests.cpp" + ) + add_executable("os::kernel_tests" ALIAS "kernel_tests") + + target_link_libraries("kernel_tests" PRIVATE + "os::kernel_test_support" + ) + + set_target_properties("kernel_tests" PROPERTIES + C_CLANG_TIDY "" + CXX_CLANG_TIDY "" + EXCLUDE_FROM_ALL NO + ) + + enable_coverage("kernel_tests") + catch_discover_tests("os::kernel_tests") endif() diff --git a/kernel/include/kernel/tests/cpu.hpp b/kernel/include/kernel/tests/cpu.hpp new file mode 100644 index 0000000..81c0c6f --- /dev/null +++ b/kernel/include/kernel/tests/cpu.hpp @@ -0,0 +1,18 @@ +#ifndef TEACHOS_KERNEL_TESTS_CPU_HPP +#define TEACHOS_KERNEL_TESTS_CPU_HPP + +#include + +namespace kernel::tests::cpu +{ + + struct halt : std::runtime_error + { + halt() + : std::runtime_error{"CPU halt requested!"} + {} + }; + +} // namespace kernel::tests::cpu + +#endif \ No newline at end of file diff --git a/kernel/include/kernel/tests/log_buffer.hpp b/kernel/include/kernel/tests/log_buffer.hpp new file mode 100644 index 0000000..5f2a1a7 --- /dev/null +++ b/kernel/include/kernel/tests/log_buffer.hpp @@ -0,0 +1,32 @@ +#ifndef KERNEL_TESTS_LOG_BUFFER_HPP +#define KERNEL_TESTS_LOG_BUFFER_HPP + +#include +#include + +namespace kernel::tests::log_buffer +{ + + //! Append a message to the testing log buffer. + //! + //! @param message The message to append. + auto append(std::string const & message) -> void; + + //! Clear the testing log buffer. + auto clear() -> void; + + //! Get the testing log buffer as a single string. + //! + //! @return The testing log buffer as a single string. + auto flat_messages() -> std::string; + + //! Get the testing log buffer. + //! + //! @note Messages may be split across multiple entries if they are longer than the internal kernel print buffer size. + //! + //! @return The testing log buffer. + auto messages() -> std::vector const &; + +} // namespace kernel::tests::log_buffer + +#endif \ No newline at end of file diff --git a/kernel/include/kernel/tests/simulated_memory.hpp b/kernel/include/kernel/tests/simulated_memory.hpp new file mode 100644 index 0000000..156b1e1 --- /dev/null +++ b/kernel/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 + +#include + +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/kapi/cpu.tests.cpp b/kernel/kapi/cpu.tests.cpp new file mode 100644 index 0000000..6fe026b --- /dev/null +++ b/kernel/kapi/cpu.tests.cpp @@ -0,0 +1,19 @@ +#include "kapi/cpu.hpp" + +#include "kernel/tests/cpu.hpp" + +#include + +SCENARIO("Kernel testing kapi::cpu shims", "[support]") +{ + GIVEN("the test support infrastructure is initialized") + { + WHEN("a CPU halt is requested") + { + THEN("the correct exception is thrown") + { + REQUIRE_THROWS_AS(kapi::cpu::halt(), kernel::tests::cpu::halt); + } + } + } +} \ No newline at end of file diff --git a/kernel/kapi/system.tests.cpp b/kernel/kapi/system.tests.cpp new file mode 100644 index 0000000..c130b54 --- /dev/null +++ b/kernel/kapi/system.tests.cpp @@ -0,0 +1,30 @@ +#include "kapi/system.hpp" + +#include "kernel/tests/cpu.hpp" +#include "kernel/tests/log_buffer.hpp" + +#include + +#include + +SCENARIO("Kernel testing kapi::system shims", "[support]") +{ + GIVEN("the test support infrastructure is initialized") + { + WHEN("a the system panics") + { + kernel::tests::log_buffer::clear(); + + THEN("the correct exception is thrown") + { + REQUIRE_THROWS_AS(kapi::system::panic("[kernel:tests] Test Panic"), kernel::tests::cpu::halt); + } + + THEN("the message is appended to the log buffer") + { + CHECK_THROWS(kapi::system::panic("[kernel:tests] Test Panic")); + REQUIRE(kernel::tests::log_buffer::flat_messages().contains("[kernel:tests] Test Panic")); + } + } + } +} \ No newline at end of file diff --git a/kernel/kstd/print.tests.cpp b/kernel/kstd/print.tests.cpp new file mode 100644 index 0000000..2ab829c --- /dev/null +++ b/kernel/kstd/print.tests.cpp @@ -0,0 +1,23 @@ +#include "kstd/print" + +#include "kernel/tests/log_buffer.hpp" + +#include + +SCENARIO("Kernel testing kstd shims", "[support]") +{ + GIVEN("the test support infrastructure is initialized") + { + WHEN("a regular print is issued") + { + kernel::tests::log_buffer::clear(); + + kstd::println("[kernel:tests] Test Print"); + + THEN("the message is appended to the log buffer") + { + REQUIRE(kernel::tests::log_buffer::flat_messages().contains("[kernel:tests] Test Print")); + } + } + } +} \ No newline at end of file diff --git a/kernel/src/main.tests.cpp b/kernel/src/main.tests.cpp new file mode 100644 index 0000000..b3ae142 --- /dev/null +++ b/kernel/src/main.tests.cpp @@ -0,0 +1,38 @@ +#include "kapi/interrupts.hpp" +#include "kapi/memory.hpp" +#include +#include + +#include + +auto main(int argc, char ** argv) -> int +{ + auto session = Catch::Session{}; + + if (auto result = session.applyCommandLine(argc, argv); result != 0) + { + return result; + } + + auto const & config = session.configData(); + auto skip_init = config.listTests || // + config.listTags || // + config.listReporters || // + config.listListeners || // + config.showHelp; + + if (!skip_init) + { + kapi::cio::init(); + kapi::cpu::init(); + 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 session.run(); +} diff --git a/kernel/src/test_support/kapi/cio.cpp b/kernel/src/test_support/kapi/cio.cpp new file mode 100644 index 0000000..6359fa8 --- /dev/null +++ b/kernel/src/test_support/kapi/cio.cpp @@ -0,0 +1,38 @@ +#include + +#include "kernel/tests/log_buffer.hpp" + +#include +#include +#include + +namespace kapi::cio +{ + + namespace + { + + class test_output_device : public output_device + { + public: + test_output_device() = default; + + auto write(output_stream stream, std::string_view text) -> void override + { + auto & standard_stream = stream == output_stream::stdout ? std::cout : std::cerr; + standard_stream << text; + if (text != "\n") + { + kernel::tests::log_buffer::append(std::string{text}); + } + } + } device{}; + + } // namespace + + auto init() -> void + { + set_output_device(device); + } + +} // namespace kapi::cio \ No newline at end of file diff --git a/kernel/src/test_support/kapi/cpu.cpp b/kernel/src/test_support/kapi/cpu.cpp new file mode 100644 index 0000000..3ecaadc --- /dev/null +++ b/kernel/src/test_support/kapi/cpu.cpp @@ -0,0 +1,29 @@ +#include "kernel/tests/cpu.hpp" + +#include + +#include +#include + +namespace kapi::cpu +{ + + auto init() -> void + { + auto static initialized = std::atomic_flag{}; + if (initialized.test_and_set()) + { + throw std::logic_error("kapi::cpu::init() called more than once"); + } + + // TODO: make sure that simulated interrupt can run. + + return; + } + + auto halt() -> void + { + throw kernel::tests::cpu::halt{}; + } + +} // namespace kapi::cpu \ No newline at end of file diff --git a/kernel/src/test_support/kapi/interrupts.cpp b/kernel/src/test_support/kapi/interrupts.cpp new file mode 100644 index 0000000..0077266 --- /dev/null +++ b/kernel/src/test_support/kapi/interrupts.cpp @@ -0,0 +1,11 @@ +#include + +namespace kapi::interrupts +{ + + auto enable() -> void + { + // TODO: enable simulated interrupts. + } + +} // namespace kapi::interrupts \ No newline at end of file diff --git a/kernel/src/test_support/kapi/memory.cpp b/kernel/src/test_support/kapi/memory.cpp new file mode 100644 index 0000000..6de2f60 --- /dev/null +++ b/kernel/src/test_support/kapi/memory.cpp @@ -0,0 +1,86 @@ +#include "kapi/memory.hpp" + +#include + +#include "kernel/tests/simulated_memory.hpp" + +#include +#include + +#include +#include +#include +#include + +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> override + { + auto start = next_free_frame; + next_free_frame += count; + return std::pair{frame{start}, count}; + } + + auto release_many(std::pair) -> 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(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 + { + 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/src/test_support/log_buffer.cpp b/kernel/src/test_support/log_buffer.cpp new file mode 100644 index 0000000..9e30afb --- /dev/null +++ b/kernel/src/test_support/log_buffer.cpp @@ -0,0 +1,39 @@ +#include "kernel/tests/log_buffer.hpp" + +#include +#include +#include + +namespace kernel::tests::log_buffer +{ + + namespace + { + std::vector recorded_messages{}; + } + + auto append(std::string const & message) -> void + { + recorded_messages.push_back(message); + } + + auto clear() -> void + { + recorded_messages.clear(); + } + + auto flat_messages() -> std::string + { + return std::ranges::fold_left(recorded_messages, std::string{}, + [](std::string accumulator, std::string const & message) { + accumulator += message; + return accumulator; + }); + } + + auto messages() -> std::vector const & + { + return recorded_messages; + } + +} // namespace kernel::tests::log_buffer diff --git a/kernel/src/test_support/simulated_memory.cpp b/kernel/src/test_support/simulated_memory.cpp new file mode 100644 index 0000000..9a9b354 --- /dev/null +++ b/kernel/src/test_support/simulated_memory.cpp @@ -0,0 +1,33 @@ +#include "kernel/tests/simulated_memory.hpp" + +#include + +#include +#include + +namespace kernel::tests::simulated_memory +{ + + namespace + { + auto constinit ram_storage = std::vector{}; + auto constinit pmm_storage = std::vector{}; + } // 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 diff --git a/kernel/tests/CMakeLists.txt b/kernel/tests/CMakeLists.txt deleted file mode 100644 index 0855520..0000000 --- a/kernel/tests/CMakeLists.txt +++ /dev/null @@ -1,64 +0,0 @@ -#[============================================================================[ -# Kernel Test Support (Fakes, Stubs, Mocks, etc.) -#]============================================================================] - -add_library("kernel_test_support" - "kapi/cio.cpp" - "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 - "include" -) - -target_link_libraries("kernel_test_support" PUBLIC - "os::kapi" - "os::kernel" - "Catch2::Catch2" -) - -add_library("os::kernel_test_support" ALIAS "kernel_test_support") - -#[============================================================================[ -# Kernel Tests -#]============================================================================] - -add_executable("kernel_tests" - "src/test_support.tests.cpp" -) - -target_include_directories("kernel_tests" PRIVATE - "include" -) - -target_link_libraries("kernel_tests" PRIVATE - "os::kernel_test_support" - "libs::kstd" -) - -set_target_properties("kernel_tests" PROPERTIES - C_CLANG_TIDY "" - CXX_CLANG_TIDY "" - EXCLUDE_FROM_ALL NO -) - -enable_coverage("kernel_tests") - -add_executable("os::kernel_tests" ALIAS "kernel_tests") - -catch_discover_tests("os::kernel_tests") \ No newline at end of file diff --git a/kernel/tests/include/kernel/tests/cpu.hpp b/kernel/tests/include/kernel/tests/cpu.hpp deleted file mode 100644 index 81c0c6f..0000000 --- a/kernel/tests/include/kernel/tests/cpu.hpp +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef TEACHOS_KERNEL_TESTS_CPU_HPP -#define TEACHOS_KERNEL_TESTS_CPU_HPP - -#include - -namespace kernel::tests::cpu -{ - - struct halt : std::runtime_error - { - halt() - : std::runtime_error{"CPU halt requested!"} - {} - }; - -} // namespace kernel::tests::cpu - -#endif \ No newline at end of file diff --git a/kernel/tests/include/kernel/tests/log_buffer.hpp b/kernel/tests/include/kernel/tests/log_buffer.hpp deleted file mode 100644 index 5f2a1a7..0000000 --- a/kernel/tests/include/kernel/tests/log_buffer.hpp +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef KERNEL_TESTS_LOG_BUFFER_HPP -#define KERNEL_TESTS_LOG_BUFFER_HPP - -#include -#include - -namespace kernel::tests::log_buffer -{ - - //! Append a message to the testing log buffer. - //! - //! @param message The message to append. - auto append(std::string const & message) -> void; - - //! Clear the testing log buffer. - auto clear() -> void; - - //! Get the testing log buffer as a single string. - //! - //! @return The testing log buffer as a single string. - auto flat_messages() -> std::string; - - //! Get the testing log buffer. - //! - //! @note Messages may be split across multiple entries if they are longer than the internal kernel print buffer size. - //! - //! @return The testing log buffer. - auto messages() -> std::vector const &; - -} // namespace kernel::tests::log_buffer - -#endif \ No newline at end of file diff --git a/kernel/tests/include/kernel/tests/simulated_memory.hpp b/kernel/tests/include/kernel/tests/simulated_memory.hpp deleted file mode 100644 index 156b1e1..0000000 --- a/kernel/tests/include/kernel/tests/simulated_memory.hpp +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef TEACHOS_KERNEL_TESTS_SIMULATED_MEMORY_HPP -#define TEACHOS_KERNEL_TESTS_SIMULATED_MEMORY_HPP - -#include - -#include - -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/cio.cpp b/kernel/tests/kapi/cio.cpp deleted file mode 100644 index 6359fa8..0000000 --- a/kernel/tests/kapi/cio.cpp +++ /dev/null @@ -1,38 +0,0 @@ -#include - -#include "kernel/tests/log_buffer.hpp" - -#include -#include -#include - -namespace kapi::cio -{ - - namespace - { - - class test_output_device : public output_device - { - public: - test_output_device() = default; - - auto write(output_stream stream, std::string_view text) -> void override - { - auto & standard_stream = stream == output_stream::stdout ? std::cout : std::cerr; - standard_stream << text; - if (text != "\n") - { - kernel::tests::log_buffer::append(std::string{text}); - } - } - } device{}; - - } // namespace - - auto init() -> void - { - set_output_device(device); - } - -} // namespace kapi::cio \ No newline at end of file diff --git a/kernel/tests/kapi/cpu.cpp b/kernel/tests/kapi/cpu.cpp deleted file mode 100644 index 3ecaadc..0000000 --- a/kernel/tests/kapi/cpu.cpp +++ /dev/null @@ -1,29 +0,0 @@ -#include "kernel/tests/cpu.hpp" - -#include - -#include -#include - -namespace kapi::cpu -{ - - auto init() -> void - { - auto static initialized = std::atomic_flag{}; - if (initialized.test_and_set()) - { - throw std::logic_error("kapi::cpu::init() called more than once"); - } - - // TODO: make sure that simulated interrupt can run. - - return; - } - - auto halt() -> void - { - throw kernel::tests::cpu::halt{}; - } - -} // namespace kapi::cpu \ No newline at end of file diff --git a/kernel/tests/kapi/interrupts.cpp b/kernel/tests/kapi/interrupts.cpp deleted file mode 100644 index 0077266..0000000 --- a/kernel/tests/kapi/interrupts.cpp +++ /dev/null @@ -1,11 +0,0 @@ -#include - -namespace kapi::interrupts -{ - - auto enable() -> void - { - // TODO: enable simulated interrupts. - } - -} // namespace kapi::interrupts \ No newline at end of file diff --git a/kernel/tests/kapi/memory.cpp b/kernel/tests/kapi/memory.cpp deleted file mode 100644 index 6de2f60..0000000 --- a/kernel/tests/kapi/memory.cpp +++ /dev/null @@ -1,86 +0,0 @@ -#include "kapi/memory.hpp" - -#include - -#include "kernel/tests/simulated_memory.hpp" - -#include -#include - -#include -#include -#include -#include - -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> override - { - auto start = next_free_frame; - next_free_frame += count; - return std::pair{frame{start}, count}; - } - - auto release_many(std::pair) -> 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(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 - { - 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/log_buffer.cpp b/kernel/tests/src/log_buffer.cpp deleted file mode 100644 index 9e30afb..0000000 --- a/kernel/tests/src/log_buffer.cpp +++ /dev/null @@ -1,39 +0,0 @@ -#include "kernel/tests/log_buffer.hpp" - -#include -#include -#include - -namespace kernel::tests::log_buffer -{ - - namespace - { - std::vector recorded_messages{}; - } - - auto append(std::string const & message) -> void - { - recorded_messages.push_back(message); - } - - auto clear() -> void - { - recorded_messages.clear(); - } - - auto flat_messages() -> std::string - { - return std::ranges::fold_left(recorded_messages, std::string{}, - [](std::string accumulator, std::string const & message) { - accumulator += message; - return accumulator; - }); - } - - auto messages() -> std::vector const & - { - return recorded_messages; - } - -} // namespace kernel::tests::log_buffer diff --git a/kernel/tests/src/main.cpp b/kernel/tests/src/main.cpp deleted file mode 100644 index b3ae142..0000000 --- a/kernel/tests/src/main.cpp +++ /dev/null @@ -1,38 +0,0 @@ -#include "kapi/interrupts.hpp" -#include "kapi/memory.hpp" -#include -#include - -#include - -auto main(int argc, char ** argv) -> int -{ - auto session = Catch::Session{}; - - if (auto result = session.applyCommandLine(argc, argv); result != 0) - { - return result; - } - - auto const & config = session.configData(); - auto skip_init = config.listTests || // - config.listTags || // - config.listReporters || // - config.listListeners || // - config.showHelp; - - if (!skip_init) - { - kapi::cio::init(); - kapi::cpu::init(); - 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 session.run(); -} diff --git a/kernel/tests/src/simulated_memory.cpp b/kernel/tests/src/simulated_memory.cpp deleted file mode 100644 index 9a9b354..0000000 --- a/kernel/tests/src/simulated_memory.cpp +++ /dev/null @@ -1,33 +0,0 @@ -#include "kernel/tests/simulated_memory.hpp" - -#include - -#include -#include - -namespace kernel::tests::simulated_memory -{ - - namespace - { - auto constinit ram_storage = std::vector{}; - auto constinit pmm_storage = std::vector{}; - } // 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 diff --git a/kernel/tests/src/test_support.tests.cpp b/kernel/tests/src/test_support.tests.cpp deleted file mode 100644 index f835e65..0000000 --- a/kernel/tests/src/test_support.tests.cpp +++ /dev/null @@ -1,51 +0,0 @@ -#include "kapi/cpu.hpp" -#include "kapi/system.hpp" - -#include "kernel/tests/cpu.hpp" -#include "kernel/tests/log_buffer.hpp" - -#include - -#include - -SCENARIO("Kernel test support infrastructure", "[support]") -{ - GIVEN("the test support infrastructure is initialized") - { - WHEN("a CPU halt is requested") - { - THEN("the correct exception is thrown") - { - REQUIRE_THROWS_AS(kapi::cpu::halt(), kernel::tests::cpu::halt); - } - } - - WHEN("a the system panics") - { - kernel::tests::log_buffer::clear(); - - THEN("the correct exception is thrown") - { - REQUIRE_THROWS_AS(kapi::system::panic("[kernel:tests] Test Panic"), kernel::tests::cpu::halt); - } - - THEN("the message is appended to the log buffer") - { - CHECK_THROWS(kapi::system::panic("[kernel:tests] Test Panic")); - REQUIRE(kernel::tests::log_buffer::flat_messages().contains("[kernel:tests] Test Panic")); - } - } - - WHEN("a regular print is issued") - { - kernel::tests::log_buffer::clear(); - - kstd::println("[kernel:tests] Test Print"); - - THEN("the message is appended to the log buffer") - { - REQUIRE(kernel::tests::log_buffer::flat_messages().contains("[kernel:tests] Test Print")); - } - } - } -} \ No newline at end of file -- cgit v1.2.3 From 6c1921d77a6d23bd5850db5b8db20e0f1bc67f40 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Wed, 1 Apr 2026 12:23:00 +0200 Subject: kernel/test