diff options
Diffstat (limited to 'kernel/src/test_support')
20 files changed, 844 insertions, 0 deletions
diff --git a/kernel/src/test_support/devices/block_device.cpp b/kernel/src/test_support/devices/block_device.cpp new file mode 100644 index 0000000..9a9e544 --- /dev/null +++ b/kernel/src/test_support/devices/block_device.cpp @@ -0,0 +1,61 @@ +#include <kernel/test_support/devices/block_device.hpp> + +#include <kernel/devices/block_device.hpp> + +#include <kstd/string> +#include <kstd/vector> + +#include <algorithm> +#include <cstddef> +#include <cstdint> +#include <cstring> +#include <string.h> + +namespace kernel::tests::devices +{ + block_device::block_device(size_t major, size_t minor, kstd::string const & name, size_t block_size, + size_t initial_size) + : kernel::devices::block_device(major, minor, name, block_size) + { + data.resize(initial_size, 0); + } + + auto block_device::init() -> bool + { + return true; + } + + auto block_device::read_block(size_t block_index, void * buffer) const -> void + { + auto const offset = block_index * block_size(); + if (offset >= data.size()) + { + kstd::libc::memset(buffer, 0, block_size()); + return; + } + + auto const bytes_to_read = std::min(block_size(), data.size() - offset); + kstd::libc::memcpy(buffer, data.data() + offset, bytes_to_read); + if (bytes_to_read < block_size()) + { + kstd::libc::memset(static_cast<uint8_t *>(buffer) + bytes_to_read, 0, block_size() - bytes_to_read); + } + } + + auto block_device::write_block(size_t block_index, void const * buffer) -> void + { + auto const offset = block_index * block_size(); + auto const write_end = offset + block_size(); + if (write_end > data.size()) + { + data.resize(write_end, 0); + } + + kstd::libc::memcpy(data.data() + offset, static_cast<uint8_t const *>(buffer), block_size()); + } + + auto block_device::size() const -> size_t + { + return data.size(); + } +} // namespace kernel::tests::devices
\ No newline at end of file diff --git a/kernel/src/test_support/devices/character_device.cpp b/kernel/src/test_support/devices/character_device.cpp new file mode 100644 index 0000000..3806654 --- /dev/null +++ b/kernel/src/test_support/devices/character_device.cpp @@ -0,0 +1,19 @@ +#include <kernel/test_support/devices/character_device.hpp> + +#include <kapi/devices.hpp> + +#include <kstd/string> + +#include <cstddef> + +namespace kernel::tests::devices +{ + character_device::character_device(size_t major, size_t minor, kstd::string const & name) + : kapi::devices::device(major, minor, name) + {} + + auto character_device::init() -> bool + { + return true; + } +} // namespace kernel::tests::devices
\ No newline at end of file diff --git a/kernel/src/test_support/filesystem/ext2.cpp b/kernel/src/test_support/filesystem/ext2.cpp new file mode 100644 index 0000000..52b6efe --- /dev/null +++ b/kernel/src/test_support/filesystem/ext2.cpp @@ -0,0 +1,68 @@ +#include <kernel/test_support/filesystem/ext2.hpp> + +#include <kernel/filesystem/ext2/block_group_descriptor.hpp> +#include <kernel/filesystem/ext2/filesystem.hpp> +#include <kernel/filesystem/ext2/inode.hpp> +#include <kernel/filesystem/ext2/superblock.hpp> +#include <kernel/test_support/devices/block_device.hpp> + +#include <cstdint> +#include <cstring> + +namespace kernel::tests::filesystem::ext2 +{ + namespace + { + constexpr uint32_t root_directory_data_block = 20; + } // namespace + + auto write_bytes(kernel::tests::devices::block_device & device, size_t offset, void const * source, size_t size) + -> void + { + auto const required_size = offset + size; + if (device.data.size() < required_size) + { + device.data.resize(required_size, 0); + } + + std::memcpy(device.data.data() + offset, source, size); + } + + auto write_u32(kernel::tests::devices::block_device & device, size_t offset, uint32_t value) -> void + { + write_bytes(device, offset, &value, sizeof(value)); + } + + auto setup_mock_ext2_layout(kernel::tests::devices::block_device & device) -> void + { + auto superblock = kernel::filesystem::ext2::superblock{}; + superblock.magic = kernel::filesystem::ext2::constants::magic_number; + superblock.log_block_size = 0; + superblock.blocks_count = 64; + superblock.blocks_per_group = 64; + superblock.inodes_per_group = 32; + superblock.rev_level = 1; + superblock.inode_size = 128; + setup_mock_ext2_layout(device, superblock); + } + + auto setup_mock_ext2_layout(kernel::tests::devices::block_device & device, + kernel::filesystem::ext2::superblock const & superblock) -> void + { + write_bytes(device, kernel::filesystem::ext2::constants::superblock_offset, &superblock, sizeof(superblock)); + + auto group_descriptor = kernel::filesystem::ext2::block_group_descriptor{}; + group_descriptor.inode_table = 5; + write_bytes(device, 2048, &group_descriptor, sizeof(group_descriptor)); + + auto root_inode_data = kernel::filesystem::ext2::inode_data{}; + root_inode_data.mode = kernel::filesystem::ext2::constants::mode_directory; + root_inode_data.blocks = 2; + root_inode_data.block[0] = root_directory_data_block; + + auto const root_inode_offset = + static_cast<size_t>(group_descriptor.inode_table) * kernel::filesystem::ext2::constants::base_block_size + + (kernel::filesystem::ext2::constants::root_inode_number - 1) * superblock.inode_size; + write_bytes(device, root_inode_offset, &root_inode_data, sizeof(root_inode_data)); + } +} // namespace kernel::tests::filesystem::ext2
\ No newline at end of file diff --git a/kernel/src/test_support/filesystem/filesystem.cpp b/kernel/src/test_support/filesystem/filesystem.cpp new file mode 100644 index 0000000..ec70607 --- /dev/null +++ b/kernel/src/test_support/filesystem/filesystem.cpp @@ -0,0 +1,17 @@ +#include <kernel/test_support/filesystem/filesystem.hpp> + +#include <kernel/filesystem/inode.hpp> +#include <kernel/test_support/filesystem/inode.hpp> + +#include <kstd/memory> + +#include <string_view> + +namespace kernel::tests::filesystem +{ + auto filesystem::lookup(kstd::shared_ptr<kernel::filesystem::inode> const &, std::string_view) const + -> kstd::shared_ptr<kernel::filesystem::inode> + { + return kstd::make_shared<inode>(); + } +} // namespace kernel::tests::filesystem
\ No newline at end of file diff --git a/kernel/src/test_support/filesystem/inode.cpp b/kernel/src/test_support/filesystem/inode.cpp new file mode 100644 index 0000000..0c8d956 --- /dev/null +++ b/kernel/src/test_support/filesystem/inode.cpp @@ -0,0 +1,23 @@ +#include <kernel/test_support/filesystem/inode.hpp> + +#include <kernel/filesystem/inode.hpp> + +#include <cstddef> + +namespace kernel::tests::filesystem +{ + auto inode::read(void *, size_t, size_t size) const -> size_t + { + return size; + } + + auto inode::write(void const *, size_t, size_t size) -> size_t + { + return size; + } + + auto inode::is_regular() const -> bool + { + return true; + } +} // namespace kernel::tests::filesystem
\ No newline at end of file diff --git a/kernel/src/test_support/filesystem/storage_boot_module_fixture.cpp b/kernel/src/test_support/filesystem/storage_boot_module_fixture.cpp new file mode 100644 index 0000000..aabaace --- /dev/null +++ b/kernel/src/test_support/filesystem/storage_boot_module_fixture.cpp @@ -0,0 +1,139 @@ +#include <kernel/test_support/filesystem/storage_boot_module_fixture.hpp> + +#include <kernel/devices/storage/management.hpp> +#include <kernel/test_support/boot_modules.hpp> +#include <kernel/test_support/devices/storage/management.hpp> + +#include <kapi/boot_module/boot_module.hpp> +#include <kapi/boot_modules.hpp> +#include <kapi/memory.hpp> + +#include <cstddef> +#include <fcntl.h> +#include <filesystem> +#include <format> +#include <stdexcept> +#include <string> +#include <unistd.h> +#include <utility> +#include <vector> + +#include <sys/mman.h> +#include <sys/stat.h> + +namespace kernel::tests::filesystem +{ + storage_boot_module_fixture::mapped_image::mapped_image(std::filesystem::path path) + : file_descriptor(::open(path.c_str(), O_RDWR)) + { + if (file_descriptor < 0) + { + throw std::runtime_error{"Failed to open image file for test boot module: " + path.string()}; + } + + struct stat statistics{}; + if (::fstat(file_descriptor, &statistics) < 0) + { + throw std::runtime_error{"Failed to get statistics for image file: " + path.string()}; + } + + size = static_cast<std::size_t>(statistics.st_size); + + mapping = static_cast<std::byte *>(::mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_PRIVATE, file_descriptor, 0)); + if (mapping == MAP_FAILED) + { + throw std::runtime_error{"Failed to map image file for test boot module: " + path.string()}; + } + } + + storage_boot_module_fixture::mapped_image::~mapped_image() + { + if (mapping != nullptr) + { + ::munmap(mapping, size); + } + if (file_descriptor >= 0) + { + ::close(file_descriptor); + } + } + + storage_boot_module_fixture::mapped_image::mapped_image(mapped_image && other) noexcept + : file_descriptor{std::exchange(other.file_descriptor, -1)} + , mapping{std::exchange(other.mapping, nullptr)} + , size{std::exchange(other.size, 0)} + {} + + auto storage_boot_module_fixture::mapped_image::operator=(mapped_image && other) noexcept -> mapped_image & + { + if (this != &other) + { + file_descriptor = std::exchange(other.file_descriptor, -1); + mapping = std::exchange(other.mapping, nullptr); + size = std::exchange(other.size, 0); + } + return *this; + } + + storage_boot_module_fixture::~storage_boot_module_fixture() + { + kernel::tests::devices::storage::management::deinit(); + kernel::tests::boot_modules::deinit(); + } + + auto storage_boot_module_fixture::setup_modules(std::size_t module_count, std::size_t module_size) -> void + { + m_module_names.clear(); + m_module_data.clear(); + m_registry = {}; + + m_module_names.reserve(module_count); + m_module_data.reserve(module_count); + + for (std::size_t i = 0; i < module_count; ++i) + { + m_module_names.push_back(std::format("test_mod{}", i)); + m_module_data.emplace_back(module_size, std::byte{static_cast<unsigned char>(0x40 + (i % 16))}); + } + + for (std::size_t i = 0; i < module_count; ++i) + { + m_registry.add_boot_module(kapi::boot_modules::boot_module{ + m_module_names[i].c_str(), kapi::memory::linear_address{m_module_data[i].data()}, m_module_data[i].size()}); + } + + kapi::boot_modules::set_boot_module_registry(m_registry); + kernel::devices::storage::management::init(); + } + + auto storage_boot_module_fixture::setup_modules_from_img(std::vector<std::string> const & module_names, + std::vector<std::filesystem::path> const & img_paths) -> void + { + m_module_names.clear(); + m_module_data.clear(); + m_registry = {}; + + if (module_names.size() != img_paths.size()) + { + throw std::invalid_argument{"Module names and image paths vectors must have the same size."}; + } + + for (size_t i = 0; i < module_names.size(); ++i) + { + setup_module_from_img(module_names[i], img_paths[i]); + } + + kapi::boot_modules::set_boot_module_registry(m_registry); + kernel::devices::storage::management::init(); + } + + auto storage_boot_module_fixture::setup_module_from_img(std::string const & module_name, + std::filesystem::path const & img_path) -> void + { + m_module_names.push_back(module_name); + auto & mapped_image = m_mapped_images.emplace_back(img_path); + + m_registry.add_boot_module(kapi::boot_modules::boot_module{ + m_module_names.back().c_str(), kapi::memory::linear_address{mapped_image.mapping}, mapped_image.size}); + } +} // namespace kernel::tests::filesystem
\ No newline at end of file diff --git a/kernel/src/test_support/filesystem/storage_boot_module_vfs_fixture.cpp b/kernel/src/test_support/filesystem/storage_boot_module_vfs_fixture.cpp new file mode 100644 index 0000000..02ccfec --- /dev/null +++ b/kernel/src/test_support/filesystem/storage_boot_module_vfs_fixture.cpp @@ -0,0 +1,31 @@ +#include <kernel/test_support/filesystem/storage_boot_module_vfs_fixture.hpp> + +#include <kernel/filesystem/vfs.hpp> +#include <kernel/test_support/filesystem/vfs.hpp> + +#include <cstddef> +#include <filesystem> +#include <string> +#include <vector> + +namespace kernel::tests::filesystem +{ + storage_boot_module_vfs_fixture::~storage_boot_module_vfs_fixture() + { + kernel::tests::filesystem::vfs::deinit(); + } + + auto storage_boot_module_vfs_fixture::setup_modules_and_init_vfs(std::size_t module_count, std::size_t module_size) + -> void + { + setup_modules(module_count, module_size); + kernel::filesystem::vfs::init(); + } + + auto storage_boot_module_vfs_fixture::setup_modules_from_img_and_init_vfs( + std::vector<std::string> const & module_names, std::vector<std::filesystem::path> const & img_paths) -> void + { + setup_modules_from_img(module_names, img_paths); + kernel::filesystem::vfs::init(); + } +} // namespace kernel::tests::filesystem
\ No newline at end of file diff --git a/kernel/src/test_support/filesystem/test_assets/README.md b/kernel/src/test_support/filesystem/test_assets/README.md new file mode 120000 index 0000000..718a227 --- /dev/null +++ b/kernel/src/test_support/filesystem/test_assets/README.md @@ -0,0 +1 @@ +/arch/x86_64/support/modules/README.md
\ No newline at end of file diff --git a/kernel/src/test_support/filesystem/test_assets/ext2_1KB_fs.img b/kernel/src/test_support/filesystem/test_assets/ext2_1KB_fs.img new file mode 100644 index 0000000..a5202ca --- /dev/null +++ b/kernel/src/test_support/filesystem/test_assets/ext2_1KB_fs.img @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:98ac3c1be872806e25fb14eea168ca79a91959f4e6a5ac3d00c5d8224c1f73a3 +size 10485760 diff --git a/kernel/src/test_support/filesystem/test_assets/ext2_2KB_fs.img b/kernel/src/test_support/filesystem/test_assets/ext2_2KB_fs.img new file mode 100644 index 0000000..7f297f0 --- /dev/null +++ b/kernel/src/test_support/filesystem/test_assets/ext2_2KB_fs.img @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6d9e872916e7d9107b321cc007e151899d5f19400a694666c0b24d482aef61ca +size 5242880 diff --git a/kernel/src/test_support/filesystem/test_assets/ext2_4KB_fs.img b/kernel/src/test_support/filesystem/test_assets/ext2_4KB_fs.img new file mode 100644 index 0000000..c3f6daf --- /dev/null +++ b/kernel/src/test_support/filesystem/test_assets/ext2_4KB_fs.img @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:026ca30269dbd80beb2dd74677c94676d1d4a7f6b5fe406c4ddb82836ba2dc00 +size 10485760 diff --git a/kernel/src/test_support/kapi/cio.cpp b/kernel/src/test_support/kapi/cio.cpp new file mode 100644 index 0000000..98bc99d --- /dev/null +++ b/kernel/src/test_support/kapi/cio.cpp @@ -0,0 +1,54 @@ +#include <kernel/test_support/cio.hpp> + +#include <kernel/test_support/log_buffer.hpp> + +#include <kapi/cio.hpp> + +#include <atomic> +#include <optional> +#include <stdexcept> + +namespace +{ + + auto constinit is_initialized = std::atomic_flag{}; + auto constinit device = std::optional<kernel::tests::cio::output_device>{}; + +} // namespace + +namespace kapi::cio +{ + + auto init() -> void + { + if (is_initialized.test_and_set()) + { + throw std::logic_error("kapi::cio::init() called more than once"); + } + + device.emplace(); + set_output_device(*device); + } + +} // namespace kapi::cio + +namespace kernel::tests::cio +{ + + auto deinit() -> void + { + if (!is_initialized.test()) + { + throw std::logic_error("kapi::cio::deinit() called before kapi::cio::init()"); + } + + device.reset(); + is_initialized.clear(); + } + + auto log_buffer() -> kernel::tests::log_buffer & + { + return device->log_buffer(); + } + +} // namespace kernel::tests::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..5d95633 --- /dev/null +++ b/kernel/src/test_support/kapi/cpu.cpp @@ -0,0 +1,52 @@ +#include <kernel/test_support/cpu.hpp> + +#include <kapi/cpu.hpp> + +#include <atomic> +#include <stdexcept> + +namespace +{ + auto static initialized = std::atomic_flag{}; +} + +namespace kapi::cpu +{ + + auto init() -> void + { + if (initialized.test_and_set()) + { + throw std::logic_error("kapi::cpu::init() called more than once"); + } + + // TODO: make sure that simulated interrupt can run. + } + + auto halt() -> void + { + throw kernel::tests::cpu::halt{}; + } + + auto discover_topology() -> bool + { + // TODO: implement more meaningful simulated CPU topology discovery + return true; + } + +} // namespace kapi::cpu + +namespace kernel::tests::cpu +{ + + auto deinit() -> void + { + if (!initialized.test()) + { + throw std::logic_error{"kapi::cpu::reset() called before kapi::cpu::init()"}; + } + + initialized.clear(); + } + +} // namespace kernel::tests::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 <kapi/interrupts.hpp> + +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..7fc95cb --- /dev/null +++ b/kernel/src/test_support/kapi/memory.cpp @@ -0,0 +1,74 @@ +#include <kapi/memory.hpp> + +#include <kernel/test_support/bump_frame_allocator.hpp> +#include <kernel/test_support/page_mapper.hpp> + +#include <kapi/memory.hpp> + +#include <kstd/units> + +#include <optional> + +namespace +{ + //! The size of the simulated RAM. + constexpr auto physical_size = kstd::units::MiB(32); + constexpr auto virtual_size = kstd::units::GiB(1); + + constexpr auto number_of_frames = physical_size / kapi::memory::frame::size; + + auto constinit bump_allocator = std::optional<kernel::tests::bump_frame_allocator>{}; + auto constinit test_mapper = std::optional<kernel::tests::page_mapper>{}; + + auto constinit old_allocator = std::optional<kapi::memory::frame_allocator *>{}; + auto constinit old_mapper = std::optional<kapi::memory::page_mapper *>{}; + + auto handoff_to_kernel_pmm(kapi::memory::frame_allocator & new_allocator) -> void + { + auto first_free_frame = bump_allocator->next_free_frame; + auto number_of_free_frames = number_of_frames - first_free_frame; + new_allocator.release_many({kapi::memory::frame{first_free_frame}, number_of_free_frames}); + } + +} // namespace + +namespace kapi::memory +{ + + auto init() -> void + { + bump_allocator.emplace(); + test_mapper.emplace(physical_size, virtual_size); + + old_allocator = set_frame_allocator(*bump_allocator); + old_mapper = set_page_mapper(*test_mapper); + + init_pmm(physical_size / frame::size, handoff_to_kernel_pmm); + } +} // namespace kapi::memory + +namespace kernel::tests::memory +{ + + auto deinit() -> void + { + if (old_allocator && *old_allocator) + { + set_frame_allocator(**old_allocator); + } + + if (old_mapper && *old_mapper) + { + set_page_mapper(**old_mapper); + } + + bump_allocator.reset(); + test_mapper.reset(); + } + + auto virtual_base() -> kapi::memory::linear_address + { + return test_mapper->memory.virtual_base(); + } + +} // namespace kernel::tests::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..04d875b --- /dev/null +++ b/kernel/src/test_support/log_buffer.cpp @@ -0,0 +1,33 @@ +#include <kernel/test_support/log_buffer.hpp> + +#include <algorithm> +#include <string> +#include <vector> + +namespace kernel::tests +{ + + auto log_buffer::append(std::string const & message) -> void + { + m_messages.push_back(message); + } + + auto log_buffer::clear() -> void + { + m_messages.clear(); + } + + auto log_buffer::flat_messages() -> std::string + { + return std::ranges::fold_left(m_messages, std::string{}, [](std::string accumulator, std::string const & message) { + accumulator += message; + return accumulator; + }); + } + + auto log_buffer::messages() -> std::vector<std::string> const & + { + return m_messages; + } + +} // namespace kernel::tests diff --git a/kernel/src/test_support/output_device.cpp b/kernel/src/test_support/output_device.cpp new file mode 100644 index 0000000..45fb4bc --- /dev/null +++ b/kernel/src/test_support/output_device.cpp @@ -0,0 +1,28 @@ +#include <kernel/test_support/cio.hpp> +#include <kernel/test_support/log_buffer.hpp> + +#include <kapi/cio.hpp> + +#include <iostream> +#include <string> +#include <string_view> + +namespace kernel::tests::cio +{ + + auto output_device::write(kapi::cio::output_stream stream, std::string_view text) -> void + { + auto & standard_stream = stream == kapi::cio::output_stream::stdout ? std::cout : std::cerr; + standard_stream << text; + if (text != "\n") + { + m_log_buffer.append(std::string{text}); + } + } + + auto output_device::log_buffer() noexcept -> kernel::tests::log_buffer & + { + return m_log_buffer; + } + +} // namespace kernel::tests::cio
\ No newline at end of file diff --git a/kernel/src/test_support/page_mapper.cpp b/kernel/src/test_support/page_mapper.cpp new file mode 100644 index 0000000..3d50ff1 --- /dev/null +++ b/kernel/src/test_support/page_mapper.cpp @@ -0,0 +1,70 @@ +#include <kernel/test_support/page_mapper.hpp> + +#include <kapi/memory.hpp> + +#include <kstd/units> + +#include <cstddef> +#include <format> +#include <stdexcept> + +namespace kernel::tests +{ + + page_mapper::page_mapper(kstd::units::bytes physical_size, kstd::units::bytes virtual_size) + : memory{physical_size, virtual_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 virtual_base = memory.virtual_base(); + auto virtual_end = virtual_base + memory.virtual_size(); + + if (page_address >= virtual_base && page_address < virtual_end) + { + auto virtual_target = static_cast<std::byte *>(page_address); + auto physical_offset = frame.number() * kapi::memory::frame::size; + return memory.map(kapi::memory::page::size, virtual_target, physical_offset.value); + } + 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.physical_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 diff --git a/kernel/src/test_support/simulated_memory.cpp b/kernel/src/test_support/simulated_memory.cpp new file mode 100644 index 0000000..074e6b1 --- /dev/null +++ b/kernel/src/test_support/simulated_memory.cpp @@ -0,0 +1,106 @@ +#include <kernel/test_support/simulated_memory.hpp> + +#include <kapi/memory.hpp> + +#include <kstd/units> + +#include <cerrno> +#include <cstddef> +#include <cstring> +#include <format> +#include <stdexcept> +#include <unistd.h> + +#include <sys/mman.h> +#include <sys/types.h> + +namespace kernel::tests +{ + + simulated_memory::simulated_memory(kstd::units::bytes physical_size, kstd::units::bytes virtual_size) + : m_descriptor{memfd_create("teachos_simulated_memory", 0)} + , m_physical_size{physical_size} + , m_virtual_size{virtual_size} + { + if (m_descriptor < 0) + { + auto error = std::format("Failed to allocate backing memory: {}", strerror(errno)); + throw std::runtime_error(error); + } + + if (ftruncate(m_descriptor, static_cast<off_t>(m_physical_size.value)) < 0) + { + auto error = std::format("Failed to reserve backing memory: {}", strerror(errno)); + throw std::runtime_error(error); + } + + auto physical_storage = mmap(nullptr, m_physical_size.value, PROT_READ | PROT_WRITE, MAP_SHARED, m_descriptor, 0); + if (physical_storage == MAP_FAILED) + { + auto error = std::format("Failed to map backing memory: {}", strerror(errno)); + throw std::runtime_error(error); + } + + auto virtual_pointer = mmap(nullptr, virtual_size.value, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (virtual_pointer == MAP_FAILED) + { + auto error = std::format("Failed to reserve virtual memory: {}", strerror(errno)); + throw std::runtime_error(error); + } + + m_physical_base = static_cast<std::byte *>(physical_storage); + m_virtual_base = static_cast<std::byte *>(virtual_pointer); + + clear(); + } + + simulated_memory::~simulated_memory() + { + munmap(m_virtual_base, m_virtual_size.value); + munmap(m_physical_base, m_physical_size.value); + close(m_descriptor); + } + + auto simulated_memory::clear() -> void + { + std::memset(m_physical_base, 0, m_physical_size.value); + } + + auto simulated_memory::physical_base() noexcept -> std::byte * + { + return m_physical_base; + } + + auto simulated_memory::physical_base() const noexcept -> std::byte const * + { + return m_physical_base; + } + + auto simulated_memory::physical_size() const noexcept -> kstd::units::bytes + { + return m_physical_size; + } + + auto simulated_memory::virtual_base() const noexcept -> kapi::memory::linear_address + { + return kapi::memory::linear_address{m_virtual_base}; + } + + auto simulated_memory::virtual_size() const noexcept -> kstd::units::bytes + { + return m_virtual_size; + } + + auto simulated_memory::map(kstd::units::bytes size, std::byte * to, off_t offset) -> std::byte * + { + auto mapped_ptr = mmap(to, size.value, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_FIXED, m_descriptor, offset); + if (mapped_ptr == MAP_FAILED) + { + auto error = std::format("Failed to map page: {}", strerror(errno)); + throw std::runtime_error(error); + } + + return static_cast<std::byte *>(mapped_ptr); + } + +} // namespace kernel::tests
\ No newline at end of file diff --git a/kernel/src/test_support/state_reset_listener.cpp b/kernel/src/test_support/state_reset_listener.cpp new file mode 100644 index 0000000..6bb7537 --- /dev/null +++ b/kernel/src/test_support/state_reset_listener.cpp @@ -0,0 +1,48 @@ +#include <kernel/filesystem/open_file_table.hpp> +#include <kernel/test_support/boot_modules.hpp> +#include <kernel/test_support/cio.hpp> +#include <kernel/test_support/cpu.hpp> +#include <kernel/test_support/devices/storage/management.hpp> +#include <kernel/test_support/filesystem/open_file_table.hpp> +#include <kernel/test_support/filesystem/vfs.hpp> +#include <kernel/test_support/memory.hpp> + +#include <kapi/cio.hpp> +#include <kapi/cpu.hpp> +#include <kapi/memory.hpp> + +#include <catch2/catch_test_case_info.hpp> +#include <catch2/interfaces/catch_interfaces_reporter.hpp> +#include <catch2/reporters/catch_reporter_event_listener.hpp> +#include <catch2/reporters/catch_reporter_registrars.hpp> + +struct state_reset_listener : Catch::EventListenerBase +{ + using EventListenerBase::EventListenerBase; + + void testCaseStarting(Catch::TestCaseInfo const &) override + { + kernel::filesystem::open_file_table::init(); + + kapi::cio::init(); + kapi::cpu::init(); + kapi::memory::init(); + } + + void testCaseEnded(Catch::TestCaseStats const &) override + { + kernel::tests::filesystem::open_file_table::deinit(); + kernel::tests::filesystem::vfs::deinit(); + kernel::tests::boot_modules::deinit(); + kernel::tests::devices::storage::management::deinit(); + + kernel::tests::memory::deinit(); + kernel::tests::cpu::deinit(); + kernel::tests::cio::deinit(); + } +}; + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wpedantic" +CATCH_REGISTER_LISTENER(state_reset_listener); +#pragma GCC diagnostic pop
\ No newline at end of file |
