aboutsummaryrefslogtreecommitdiff
path: root/kernel/src
diff options
context:
space:
mode:
authorFelix Morgner <felix.morgner@ost.ch>2026-07-03 09:32:30 +0200
committerFelix Morgner <felix.morgner@ost.ch>2026-07-03 09:32:30 +0200
commit3012fa5dfe5dfed5e83baf9b40934ed8e8317627 (patch)
tree00d1c60a3d5d1cdfa55e0ff1691cd3362b6064ee /kernel/src
parent5d8a58d538515ffc57ddf82ba40ba763990a8696 (diff)
downloadkernel-3012fa5dfe5dfed5e83baf9b40934ed8e8317627.tar.xz
kernel-3012fa5dfe5dfed5e83baf9b40934ed8e8317627.zip
kernel: rearrange sources according to p1204
Diffstat (limited to 'kernel/src')
-rw-r--r--kernel/src/acpi/manager.cpp98
-rw-r--r--kernel/src/devices/block_device.cpp42
-rw-r--r--kernel/src/devices/block_device.tests.cpp46
-rw-r--r--kernel/src/devices/block_device_utils.cpp106
-rw-r--r--kernel/src/devices/block_device_utils.tests.cpp219
-rw-r--r--kernel/src/devices/root_bus.cpp12
-rw-r--r--kernel/src/devices/storage/controller.cpp44
-rw-r--r--kernel/src/devices/storage/management.cpp95
-rw-r--r--kernel/src/devices/storage/ram_disk/controller.cpp27
-rw-r--r--kernel/src/devices/storage/ram_disk/device.cpp71
-rw-r--r--kernel/src/devices/storage/ram_disk/device.tests.cpp116
-rw-r--r--kernel/src/filesystem/dentry.cpp95
-rw-r--r--kernel/src/filesystem/dentry.tests.cpp150
-rw-r--r--kernel/src/filesystem/devfs/filesystem.cpp81
-rw-r--r--kernel/src/filesystem/devfs/filesystem.tests.cpp72
-rw-r--r--kernel/src/filesystem/devfs/inode.cpp21
-rw-r--r--kernel/src/filesystem/devfs/inode.tests.cpp55
-rw-r--r--kernel/src/filesystem/device_inode.cpp57
-rw-r--r--kernel/src/filesystem/device_inode.tests.cpp109
-rw-r--r--kernel/src/filesystem/ext2/filesystem.cpp247
-rw-r--r--kernel/src/filesystem/ext2/filesystem.tests.cpp139
-rw-r--r--kernel/src/filesystem/ext2/inode.cpp111
-rw-r--r--kernel/src/filesystem/ext2/inode.tests.cpp376
-rw-r--r--kernel/src/filesystem/filesystem.cpp60
-rw-r--r--kernel/src/filesystem/inode.cpp24
-rw-r--r--kernel/src/filesystem/mount.cpp90
-rw-r--r--kernel/src/filesystem/mount.tests.cpp94
-rw-r--r--kernel/src/filesystem/mount_table.cpp79
-rw-r--r--kernel/src/filesystem/mount_table.tests.cpp184
-rw-r--r--kernel/src/filesystem/open_file_descriptor.cpp46
-rw-r--r--kernel/src/filesystem/open_file_descriptor.tests.cpp113
-rw-r--r--kernel/src/filesystem/open_file_table.cpp87
-rw-r--r--kernel/src/filesystem/open_file_table.tests.cpp106
-rw-r--r--kernel/src/filesystem/path.tests.cpp69
-rw-r--r--kernel/src/filesystem/rootfs/filesystem.cpp47
-rw-r--r--kernel/src/filesystem/rootfs/filesystem.tests.cpp38
-rw-r--r--kernel/src/filesystem/rootfs/inode.cpp23
-rw-r--r--kernel/src/filesystem/rootfs/inode.tests.cpp37
-rw-r--r--kernel/src/filesystem/type_registry.cpp76
-rw-r--r--kernel/src/filesystem/type_registry.tests.cpp77
-rw-r--r--kernel/src/filesystem/vfs.cpp299
-rw-r--r--kernel/src/filesystem/vfs.tests.cpp568
-rw-r--r--kernel/src/main.cpp152
-rw-r--r--kernel/src/memory.cpp61
-rw-r--r--kernel/src/memory/bitmap_allocator.cpp106
-rw-r--r--kernel/src/memory/bitmap_allocator.tests.cpp288
-rw-r--r--kernel/src/memory/block_list_allocator.cpp215
-rw-r--r--kernel/src/memory/block_list_allocator.tests.cpp85
-rw-r--r--kernel/src/memory/mmio_allocator.cpp111
-rw-r--r--kernel/src/memory/operators.cpp102
-rw-r--r--kernel/src/test_support/devices/block_device.cpp61
-rw-r--r--kernel/src/test_support/devices/character_device.cpp19
-rw-r--r--kernel/src/test_support/filesystem/ext2.cpp68
-rw-r--r--kernel/src/test_support/filesystem/filesystem.cpp17
-rw-r--r--kernel/src/test_support/filesystem/inode.cpp23
-rw-r--r--kernel/src/test_support/filesystem/storage_boot_module_fixture.cpp139
-rw-r--r--kernel/src/test_support/filesystem/storage_boot_module_vfs_fixture.cpp31
l---------kernel/src/test_support/filesystem/test_assets/README.md1
-rw-r--r--kernel/src/test_support/filesystem/test_assets/ext2_1KB_fs.img3
-rw-r--r--kernel/src/test_support/filesystem/test_assets/ext2_2KB_fs.img3
-rw-r--r--kernel/src/test_support/filesystem/test_assets/ext2_4KB_fs.img3
-rw-r--r--kernel/src/test_support/kapi/cio.cpp54
-rw-r--r--kernel/src/test_support/kapi/cpu.cpp52
-rw-r--r--kernel/src/test_support/kapi/interrupts.cpp11
-rw-r--r--kernel/src/test_support/kapi/memory.cpp74
-rw-r--r--kernel/src/test_support/log_buffer.cpp33
-rw-r--r--kernel/src/test_support/output_device.cpp28
-rw-r--r--kernel/src/test_support/page_mapper.cpp70
-rw-r--r--kernel/src/test_support/simulated_memory.cpp106
-rw-r--r--kernel/src/test_support/state_reset_listener.cpp48
70 files changed, 0 insertions, 6470 deletions
diff --git a/kernel/src/acpi/manager.cpp b/kernel/src/acpi/manager.cpp
deleted file mode 100644
index bb895fda..00000000
--- a/kernel/src/acpi/manager.cpp
+++ /dev/null
@@ -1,98 +0,0 @@
-#include <kernel/acpi/manager.hpp>
-
-#include <kapi/memory.hpp>
-#include <kapi/system.hpp>
-
-#include <acpi/acpi.hpp>
-
-#include <kstd/memory>
-#include <kstd/print>
-
-#include <algorithm>
-#include <cstddef>
-#include <cstdint>
-#include <ranges>
-#include <string_view>
-
-namespace kernel::acpi
-{
-
- manager::manager(::acpi::rsdp const & sdp)
- : m_sdp{&sdp}
- {
- if (!m_sdp->validate())
- {
- kapi::system::panic("[OS:ACPI] Invalid RSDP signature!");
- }
-
- m_extended = m_sdp->revision() >= 2;
-
- if (m_extended)
- {
- if (!static_cast<::acpi::xsdp const *>(m_sdp)->validate())
- {
- kapi::system::panic("[OS:ACPI] Invalid XSDP signature!");
- }
- }
- else
- {
- if (!m_sdp->validate())
- {
- kapi::system::panic("[OS:ACPI] Invalid RSDP checksum!");
- }
- }
-
- auto physical_address = kapi::memory::physical_address{m_sdp->table_address()};
- auto linear_address = kapi::memory::hhdm_to_linear(physical_address);
- m_rsdt = static_cast<::acpi::table_header const *>(linear_address);
- }
-
- auto manager::load_tables() -> bool
- {
- if (!::acpi::validate_checksum({reinterpret_cast<std::byte const *>(m_rsdt), m_rsdt->length().value}))
- {
- kapi::system::panic("[OS:ACPI] Invalid RSDT checksum!");
- }
-
- auto check_and_register_table = [&](auto table_address) -> void {
- auto physical_table_address = kapi::memory::physical_address{reinterpret_cast<std::uintptr_t>(table_address)};
- auto mapped_table = kapi::memory::hhdm_to_linear(physical_table_address);
- auto table = static_cast<::acpi::table_header const *>(mapped_table);
-
- if (!::acpi::validate_checksum({static_cast<std::byte const *>(mapped_table), table->length().value}))
- {
- kstd::println(kstd::print_sink::stderr, "[OS:ACPI] Invalid table checksum!");
- }
- else
- {
- kstd::println("[OS:ACPI] Found '{}' ACPI table", table->signature());
- m_tables.emplace(table->signature(), table);
- }
- };
-
- if (m_extended)
- {
- auto xsdt = static_cast<::acpi::xsdt const *>(m_rsdt);
- std::ranges::for_each(*xsdt | std::views::transform([](auto const & entry) { return entry.address(); }),
- check_and_register_table);
- }
- else
- {
- auto rsdt = static_cast<::acpi::rsdt const *>(m_rsdt);
- std::ranges::for_each(*rsdt | std::views::transform([](auto const & entry) { return entry.address(); }),
- check_and_register_table);
- }
-
- return !m_tables.empty();
- }
-
- auto manager::get_table(std::string_view signature) -> kstd::observer_ptr<::acpi::table_header const>
- {
- if (m_tables.contains(signature))
- {
- return kstd::make_observer(m_tables.at(signature));
- }
- return nullptr;
- }
-
-} // namespace kernel::acpi
diff --git a/kernel/src/devices/block_device.cpp b/kernel/src/devices/block_device.cpp
deleted file mode 100644
index 13d73acd..00000000
--- a/kernel/src/devices/block_device.cpp
+++ /dev/null
@@ -1,42 +0,0 @@
-#include <kernel/devices/block_device.hpp>
-
-#include <kapi/devices/device.hpp>
-#include <kapi/system.hpp>
-
-#include <kstd/string>
-
-#include <cstddef>
-
-namespace kernel::devices
-{
- block_device::block_device(size_t major, size_t minor, kstd::string const & name, size_t block_size)
- : kapi::devices::device(major, minor, name)
- , m_block_size(block_size)
- {
- if (m_block_size == 0)
- {
- kapi::system::panic("[DEVICES] block_device constructed with zero block size.");
- }
- }
-
- auto block_device::calculate_transfer(size_t block_index) const -> transfer_info
- {
- size_t const offset = block_index * m_block_size;
- size_t const limit = size();
-
- size_t const available = (offset < limit) ? (limit - offset) : 0;
- size_t const to_transfer = (available < m_block_size) ? available : m_block_size;
-
- return {offset, to_transfer, m_block_size - to_transfer};
- }
-
- auto block_device::block_size() const -> size_t
- {
- return m_block_size;
- }
-
- auto block_device::capacity() const -> size_t
- {
- return size();
- }
-} // namespace kernel::devices \ No newline at end of file
diff --git a/kernel/src/devices/block_device.tests.cpp b/kernel/src/devices/block_device.tests.cpp
deleted file mode 100644
index a2ddd2bb..00000000
--- a/kernel/src/devices/block_device.tests.cpp
+++ /dev/null
@@ -1,46 +0,0 @@
-#include <kernel/test_support/devices/block_device.hpp>
-
-#include <kernel/test_support/cpu.hpp>
-
-#include <kstd/memory>
-#include <kstd/print>
-#include <kstd/string>
-#include <kstd/vector>
-
-#include <catch2/catch_test_macros.hpp>
-
-#include <cstddef>
-
-SCENARIO("Block device construction", "[devices][block_device]")
-{
- GIVEN("parameters for a block device")
- {
- size_t major = 1;
- size_t minor = 0;
- kstd::string name = "test_block_device";
- size_t block_size = 512;
-
- WHEN("constructing a block device")
- {
- auto device =
- kstd::make_shared<kernel::tests::devices::block_device>(major, minor, name, block_size, 3 * block_size);
-
- THEN("the block device has the correct properties")
- {
- REQUIRE(device->major() == major);
- REQUIRE(device->minor() == minor);
- REQUIRE(device->name() == name);
- REQUIRE(device->block_size() == block_size);
- REQUIRE(device->capacity() == 3 * 512);
- }
- }
-
- WHEN("constructing a block device with zero block size")
- {
- THEN("the constructor panics")
- {
- REQUIRE_THROWS_AS((kernel::tests::devices::block_device(major, minor, name, 0)), kernel::tests::cpu::halt);
- }
- }
- }
-}
diff --git a/kernel/src/devices/block_device_utils.cpp b/kernel/src/devices/block_device_utils.cpp
deleted file mode 100644
index 18d1e9d7..00000000
--- a/kernel/src/devices/block_device_utils.cpp
+++ /dev/null
@@ -1,106 +0,0 @@
-#include <kernel/devices/block_device_utils.hpp>
-
-#include <kernel/devices/block_device.hpp>
-
-#include <kapi/devices/device.hpp>
-#include <kapi/system.hpp>
-
-#include <kstd/cstring>
-#include <kstd/memory>
-#include <kstd/vector>
-
-#include <algorithm>
-#include <cstddef>
-
-namespace kernel::devices::block_device_utils
-{
-
- using block_op = void (*)(size_t idx, size_t off, size_t len, size_t done, devices::block_device * device,
- std::byte * scratch, void * buffer);
-
- auto process_blocks(kstd::shared_ptr<kapi::devices::device> const & device, size_t offset, size_t size, void * buffer,
- block_op op) -> size_t
- {
- if (buffer == nullptr)
- {
- kapi::system::panic("[FILESYSTEM] device_file::process_blocks called with null buffer.");
- }
-
- if (size == 0)
- {
- return 0;
- }
-
- if (!device->is_block_device())
- {
- kapi::system::panic("[FILESYSTEM] device_file: expected block_device.");
- }
-
- auto * block_dev = static_cast<devices::block_device *>(device.get());
-
- size_t const block_size = block_dev->block_size();
- size_t const capacity = block_dev->capacity();
-
- if (offset >= capacity)
- {
- return 0;
- }
- size_t const total_to_process = std::min(size, capacity - offset);
-
- kstd::vector<std::byte> scratch_buffer{block_size};
- auto processed = 0uz;
-
- while (processed < total_to_process)
- {
- size_t const absolute_offset = offset + processed;
- size_t const block_index = absolute_offset / block_size;
- size_t const in_block_offset = absolute_offset % block_size;
- size_t const chunk_size = std::min(total_to_process - processed, block_size - in_block_offset);
-
- op(block_index, in_block_offset, chunk_size, processed, block_dev, scratch_buffer.data(), buffer);
-
- processed += chunk_size;
- }
-
- return processed;
- }
-
- auto read(kstd::shared_ptr<kapi::devices::device> const & device, void * buffer, size_t offset, size_t size) -> size_t
- {
- return process_blocks(device, offset, size, buffer,
- [](size_t idx, size_t off, size_t len, size_t done, devices::block_device * device,
- std::byte * scratch, void * buffer) {
- auto * out = static_cast<std::byte *>(buffer);
- if (off == 0 && len == device->block_size())
- {
- device->read_block(idx, out + done);
- }
- else
- {
- device->read_block(idx, scratch);
- kstd::libc::memcpy(out + done, scratch + off, len);
- }
- });
- }
-
- auto write(kstd::shared_ptr<kapi::devices::device> const & device, void const * buffer, size_t offset, size_t size)
- -> size_t
- {
- return process_blocks(device, offset, size, const_cast<void *>(buffer),
- [](size_t idx, size_t off, size_t len, size_t done, devices::block_device * device,
- std::byte * scratch, void * buffer) {
- auto const * in = static_cast<std::byte const *>(buffer);
- if (off == 0 && len == device->block_size())
- {
- device->write_block(idx, in + done);
- }
- else
- {
- device->read_block(idx, scratch);
- kstd::libc::memcpy(scratch + off, in + done, len);
- device->write_block(idx, scratch);
- }
- });
- }
-
-} // namespace kernel::devices::block_device_utils \ No newline at end of file
diff --git a/kernel/src/devices/block_device_utils.tests.cpp b/kernel/src/devices/block_device_utils.tests.cpp
deleted file mode 100644
index e2e1e65e..00000000
--- a/kernel/src/devices/block_device_utils.tests.cpp
+++ /dev/null
@@ -1,219 +0,0 @@
-#include <kernel/devices/block_device_utils.hpp>
-
-#include <kernel/test_support/cpu.hpp>
-#include <kernel/test_support/devices/block_device.hpp>
-#include <kernel/test_support/devices/character_device.hpp>
-
-#include <kstd/memory>
-#include <kstd/print>
-#include <kstd/vector>
-
-#include <catch2/catch_test_macros.hpp>
-
-#include <cstddef>
-#include <cstdint>
-
-SCENARIO("reading from a block device with block_device_utils", "[devices][block_device_utils]")
-{
- GIVEN("a block device with known data")
- {
- auto const block_size = 512;
- auto device = kstd::make_shared<kernel::tests::devices::block_device>(0, 0, "test_block_device", block_size);
- kstd::vector<uint8_t> block_data(block_size);
- for (size_t i = 0; i < block_data.size(); ++i)
- {
- block_data[i] = static_cast<uint8_t>(i % 256);
- }
- device->write_block(0, block_data.data());
- device->write_block(1, block_data.data());
-
- WHEN("reading from the block device using block_device_utils")
- {
- kstd::vector<uint8_t> read_buffer(block_size);
- auto bytes_read = kernel::devices::block_device_utils::read(device, read_buffer.data(), 0, read_buffer.size());
-
- THEN("the correct number of bytes is read")
- {
- REQUIRE(bytes_read == read_buffer.size());
- }
-
- THEN("the data read matches the data written to the block device")
- {
- REQUIRE(read_buffer == block_data);
- }
- }
-
- WHEN("reading over block boundaries")
- {
- kstd::vector<uint8_t> read_buffer(1024);
- auto bytes_read = kernel::devices::block_device_utils::read(device, read_buffer.data(), 256, read_buffer.size());
-
- THEN("the correct number of bytes is read")
- {
- REQUIRE(bytes_read == 1.5 * block_size);
- }
-
- THEN("the data read matches the expected data across block boundaries")
- {
- for (size_t i = 0; i < bytes_read; ++i)
- {
- uint8_t expected_value = static_cast<uint8_t>((256 + i) % 256);
- REQUIRE(read_buffer[i] == expected_value);
- }
- }
- }
-
- WHEN("reading beyond the device capacity")
- {
- kstd::vector<uint8_t> read_buffer(block_size);
- auto bytes_read = kernel::devices::block_device_utils::read(device, read_buffer.data(), 1024, read_buffer.size());
-
- THEN("no bytes are read")
- {
- REQUIRE(bytes_read == 0);
- }
- }
-
- WHEN("reading nothing")
- {
- kstd::vector<uint8_t> read_buffer(block_size);
- auto bytes_read = kernel::devices::block_device_utils::read(device, read_buffer.data(), 0, 0);
-
- THEN("no bytes are read")
- {
- REQUIRE(bytes_read == 0);
- }
- }
-
- WHEN("reading with a null buffer")
- {
- THEN("the system panics")
- {
- REQUIRE_THROWS_AS(kernel::devices::block_device_utils::read(device, nullptr, 0, 512), kernel::tests::cpu::halt);
- }
- }
- }
-}
-
-SCENARIO("writing to a block device using block_device_utils", "[devices][block_device_utils]")
-{
- GIVEN("a block device")
- {
- auto const block_size = 512;
- auto device =
- kstd::make_shared<kernel::tests::devices::block_device>(0, 0, "test_block_device", block_size, 2 * block_size);
-
- WHEN("writing to the block device using block_device_utils")
- {
- kstd::vector<uint8_t> write_buffer(block_size);
- for (size_t i = 0; i < write_buffer.size(); ++i)
- {
- write_buffer[i] = static_cast<uint8_t>(i % 256);
- }
-
- auto bytes_written =
- kernel::devices::block_device_utils::write(device, write_buffer.data(), 0, write_buffer.size());
-
- THEN("the correct number of bytes is written")
- {
- REQUIRE(bytes_written == write_buffer.size());
- }
-
- THEN("the data written matches the data read back from the block device")
- {
- kstd::vector<uint8_t> read_buffer(block_size);
- device->read_block(0, read_buffer.data());
- REQUIRE(read_buffer == write_buffer);
- }
- }
-
- WHEN("writing over block boundaries")
- {
- kstd::vector<uint8_t> write_buffer(2 * block_size);
- for (size_t i = 0; i < write_buffer.size(); ++i)
- {
- write_buffer[i] = static_cast<uint8_t>(i % 256);
- }
-
- auto bytes_written =
- kernel::devices::block_device_utils::write(device, write_buffer.data(), 256, write_buffer.size());
-
- THEN("the correct number of bytes is written")
- {
- REQUIRE(bytes_written == 1.5 * block_size);
- }
-
- THEN("the data written matches the data read back from the block device across block boundaries")
- {
- kstd::vector<uint8_t> read_buffer(2 * block_size);
- auto bytes_read = kernel::devices::block_device_utils::read(device, read_buffer.data(), 256, 2 * block_size);
-
- for (size_t i = 0; i < bytes_read; ++i)
- {
- REQUIRE(read_buffer[i] == write_buffer[i]);
- }
- }
- }
-
- WHEN("writing beyond the device capacity")
- {
- kstd::vector<uint8_t> write_buffer(block_size);
- auto bytes_written =
- kernel::devices::block_device_utils::write(device, write_buffer.data(), 1024, write_buffer.size());
-
- THEN("no bytes are written")
- {
- REQUIRE(bytes_written == 0);
- }
- }
-
- WHEN("writing nothing")
- {
- kstd::vector<uint8_t> write_buffer(block_size);
- auto bytes_written = kernel::devices::block_device_utils::write(device, write_buffer.data(), 0, 0);
-
- THEN("no bytes are written")
- {
- REQUIRE(bytes_written == 0);
- }
- }
-
- WHEN("writing with a null buffer")
- {
- THEN("the system panics")
- {
- REQUIRE_THROWS_AS(kernel::devices::block_device_utils::write(device, nullptr, 0, block_size),
- kernel::tests::cpu::halt);
- }
- }
- }
-}
-
-SCENARIO("block_device_utils with a non-block device", "[devices][block_device_utils]")
-{
- GIVEN("a non-block device")
- {
- auto device = kstd::make_shared<kernel::tests::devices::character_device>(0, 0, "test_character_device");
-
- WHEN("attempting to read from the non-block device using block_device_utils")
- {
- kstd::vector<uint8_t> read_buffer(512);
- THEN("the system panics")
- {
- REQUIRE_THROWS_AS(kernel::devices::block_device_utils::read(device, read_buffer.data(), 0, read_buffer.size()),
- kernel::tests::cpu::halt);
- }
- }
-
- WHEN("attempting to write to the non-block device using block_device_utils")
- {
- kstd::vector<uint8_t> write_buffer(512);
- THEN("the system panics")
- {
- REQUIRE_THROWS_AS(
- kernel::devices::block_device_utils::write(device, write_buffer.data(), 0, write_buffer.size()),
- kernel::tests::cpu::halt);
- }
- }
- }
-}
diff --git a/kernel/src/devices/root_bus.cpp b/kernel/src/devices/root_bus.cpp
deleted file mode 100644
index 1b754f23..00000000
--- a/kernel/src/devices/root_bus.cpp
+++ /dev/null
@@ -1,12 +0,0 @@
-#include <kernel/devices/root_bus.hpp>
-
-#include <kapi/devices.hpp>
-
-namespace kernel::devices
-{
-
- root_bus::root_bus()
- : kapi::devices::bus{0, 0, "system"}
- {}
-
-} // namespace kernel::devices \ No newline at end of file
diff --git a/kernel/src/devices/storage/controller.cpp b/kernel/src/devices/storage/controller.cpp
deleted file mode 100644
index 171b918e..00000000
--- a/kernel/src/devices/storage/controller.cpp
+++ /dev/null
@@ -1,44 +0,0 @@
-#include <kernel/devices/storage/controller.hpp>
-
-#include <kapi/devices/device.hpp>
-
-#include <kstd/memory>
-#include <kstd/vector>
-
-#include <algorithm>
-#include <cstddef>
-
-namespace kernel::devices::storage
-{
- auto controller::set_ids(size_t major, size_t minors_per_dev) -> void
- {
- m_major = major;
- m_minors_per_device = minors_per_dev;
- }
-
- auto controller::major() const -> size_t
- {
- return m_major;
- }
-
- auto controller::device_by_minor(size_t minor) const -> kstd::shared_ptr<kapi::devices::device>
- {
- auto it = std::ranges::find_if(m_devices, [minor](auto const & device) { return device->minor() == minor; });
-
- if (it != m_devices.end())
- {
- return *it;
- }
- return nullptr;
- }
-
- auto controller::devices_count() const -> size_t
- {
- return m_devices.size();
- }
-
- auto controller::all_devices() const -> kstd::vector<kstd::shared_ptr<kapi::devices::device>> const &
- {
- return m_devices;
- }
-} // namespace kernel::devices::storage \ No newline at end of file
diff --git a/kernel/src/devices/storage/management.cpp b/kernel/src/devices/storage/management.cpp
deleted file mode 100644
index 06efc27d..00000000
--- a/kernel/src/devices/storage/management.cpp
+++ /dev/null
@@ -1,95 +0,0 @@
-#include <kernel/devices/storage/management.hpp>
-
-#include <kernel/devices/storage/controller.hpp>
-#include <kernel/devices/storage/ram_disk/controller.hpp>
-
-#include <kapi/boot_modules.hpp>
-#include <kapi/devices/device.hpp>
-#include <kapi/system.hpp>
-
-#include <kstd/memory>
-#include <kstd/vector>
-
-#include <algorithm>
-#include <cstddef>
-#include <optional>
-#include <ranges>
-
-namespace
-{
- constexpr size_t static minors_per_device = 16;
- constexpr size_t static start_major = 1;
- constinit size_t static next_free_major = start_major;
-
- constinit auto static storage_management = std::optional<kernel::devices::storage::management>{};
-} // namespace
-
-namespace kernel::devices::storage
-{
- auto management::init() -> void
- {
- if (storage_management)
- {
- kapi::system::panic("[DEVICES] Storage management has already been initialized.");
- }
- storage_management.emplace(management{});
-
- auto ram_disk_controller = kstd::make_shared<ram_disk::controller>(&kapi::boot_modules::get_boot_module_registry());
- storage_management->add_controller(ram_disk_controller);
-
- std::ranges::for_each(storage_management->m_controllers, [](auto controller) { controller->probe(); });
- }
-
- auto management::get() -> management &
- {
- if (!storage_management)
- {
- kapi::system::panic("[DEVICES] Storage management has not been initialized.");
- }
-
- return *storage_management;
- }
-
- auto management::add_controller(kstd::shared_ptr<controller> const & controller) -> void
- {
- controller->set_ids(next_free_major++, minors_per_device);
- m_controllers.push_back(controller);
- }
-
- auto management::all_controllers() const -> kstd::vector<kstd::shared_ptr<controller>> const &
- {
- return m_controllers;
- }
-
- auto management::device_by_major_minor(size_t major, size_t minor) -> kstd::shared_ptr<kapi::devices::device>
- {
- auto found = std::ranges::find_if(m_controllers, [=](auto const & controller) {
- if (controller != nullptr && controller->major() == major)
- {
- return controller->device_by_minor(minor) != nullptr;
- }
- return false;
- });
-
- if (found != std::ranges::cend(m_controllers))
- {
- return found->get()->device_by_minor(minor);
- }
-
- return nullptr;
- }
-
- auto management::determine_boot_device() -> kstd::shared_ptr<kapi::devices::device>
- {
- return device_by_major_minor(start_major, 0);
- }
-} // namespace kernel::devices::storage
-
-namespace kernel::tests::devices::storage::management
-{
- auto deinit() -> void
- {
- storage_management.reset();
- next_free_major = start_major;
- }
-} // namespace kernel::tests::devices::storage::management
diff --git a/kernel/src/devices/storage/ram_disk/controller.cpp b/kernel/src/devices/storage/ram_disk/controller.cpp
deleted file mode 100644
index 30441fa5..00000000
--- a/kernel/src/devices/storage/ram_disk/controller.cpp
+++ /dev/null
@@ -1,27 +0,0 @@
-#include <kernel/devices/storage/ram_disk/controller.hpp>
-
-#include <kernel/devices/storage/ram_disk/device.hpp>
-
-#include <kapi/boot_module/boot_module_registry.hpp>
-
-#include <kstd/memory>
-
-#include <algorithm>
-#include <cstddef>
-
-namespace kernel::devices::storage::ram_disk
-{
- controller::controller(kapi::boot_modules::boot_module_registry const * registry)
- : m_boot_module_registry(registry)
- {}
-
- auto controller::probe() -> void
- {
- size_t current_device_index = 0;
-
- std::ranges::for_each(*m_boot_module_registry, [this, &current_device_index](auto const & module) {
- auto const minor = current_device_index++ * m_minors_per_device;
- m_devices.push_back(kstd::make_shared<device>(module, m_major, minor));
- });
- }
-} // namespace kernel::devices::storage::ram_disk \ No newline at end of file
diff --git a/kernel/src/devices/storage/ram_disk/device.cpp b/kernel/src/devices/storage/ram_disk/device.cpp
deleted file mode 100644
index 1557204b..00000000
--- a/kernel/src/devices/storage/ram_disk/device.cpp
+++ /dev/null
@@ -1,71 +0,0 @@
-#include <kernel/devices/storage/ram_disk/device.hpp>
-
-#include <kernel/devices/block_device.hpp>
-
-#include <kapi/boot_module/boot_module.hpp>
-#include <kapi/system.hpp>
-
-#include <kstd/cstring>
-#include <kstd/string>
-
-#include <cstddef>
-
-namespace kernel::devices::storage::ram_disk
-{
- namespace
- {
- constexpr size_t ram_disk_block_size = 512uz;
- } // namespace
-
- device::device(kapi::boot_modules::boot_module const & module, size_t major, size_t minor)
- : block_device(major, minor, "ram" + kstd::to_string(minor), ram_disk_block_size)
- , m_boot_module(module)
- {}
-
- auto device::init() -> bool
- {
- return m_boot_module.start_address.raw() != 0 && m_boot_module.size > 0;
- }
-
- auto device::read_block(size_t block_index, void * buffer) const -> void
- {
- if (buffer == nullptr)
- {
- kapi::system::panic("[RAM DISK DEVICE] read_block called with null buffer.");
- }
-
- auto const info = calculate_transfer(block_index);
-
- if (info.to_transfer > 0)
- {
- auto const src = static_cast<std::byte const *>(m_boot_module.start_address) + info.offset;
- kstd::libc::memcpy(buffer, src, info.to_transfer);
- }
-
- if (info.remainder > 0)
- {
- kstd::libc::memset(static_cast<std::byte *>(buffer) + info.to_transfer, 0, info.remainder);
- }
- }
-
- auto device::write_block(size_t block_index, void const * buffer) -> void
- {
- if (buffer == nullptr)
- {
- kapi::system::panic("[RAM DISK DEVICE] write_block called with null buffer.");
- }
-
- auto const info = calculate_transfer(block_index);
-
- if (info.to_transfer > 0)
- {
- auto const dest = static_cast<std::byte *>(m_boot_module.start_address) + info.offset;
- kstd::libc::memcpy(dest, buffer, info.to_transfer);
- }
- }
-
- auto device::size() const -> size_t
- {
- return m_boot_module.size;
- }
-} // namespace kernel::devices::storage::ram_disk \ No newline at end of file
diff --git a/kernel/src/devices/storage/ram_disk/device.tests.cpp b/kernel/src/devices/storage/ram_disk/device.tests.cpp
deleted file mode 100644
index d0fab76b..00000000
--- a/kernel/src/devices/storage/ram_disk/device.tests.cpp
+++ /dev/null
@@ -1,116 +0,0 @@
-#include <kernel/devices/storage/ram_disk/device.hpp>
-
-#include <kapi/boot_module/boot_module.hpp>
-#include <kapi/memory.hpp>
-
-#include <catch2/catch_test_macros.hpp>
-#include <catch2/matchers/catch_matchers.hpp>
-#include <catch2/matchers/catch_matchers_range_equals.hpp>
-
-#include <cstddef>
-#include <ranges>
-#include <stdexcept>
-#include <vector>
-
-SCENARIO("RAM Disk Device Construction and Initialization", "[ram_disk_device]")
-{
- GIVEN("an empty boot module")
- {
- kapi::boot_modules::boot_module boot_module{};
- boot_module.start_address = kapi::memory::linear_address{nullptr};
- boot_module.size = 0;
-
- WHEN("constructing the device")
- {
- kernel::devices::storage::ram_disk::device device{boot_module, 0, 0};
-
- THEN("init return false")
- {
- REQUIRE_FALSE(device.init());
- }
- }
- }
-
- GIVEN("a boot module with a valid start address and size")
- {
- kapi::boot_modules::boot_module boot_module{};
- boot_module.start_address = kapi::memory::linear_address{reinterpret_cast<std::byte *>(0x1000)};
- boot_module.size = 512;
-
- WHEN("constructing the device")
- {
- kernel::devices::storage::ram_disk::device device{boot_module, 0, 0};
-
- THEN("init return true")
- {
- REQUIRE(device.init());
- }
- }
- }
-}
-
-SCENARIO("RAM Disk Device Read and Write", "[ram_disk_device]")
-{
- GIVEN("a device initialized with a valid boot module")
- {
- auto storage = std::vector{4096, std::byte{0xff}};
- auto module =
- kapi::boot_modules::boot_module{"test_module", kapi::memory::linear_address{storage.data()}, storage.size()};
- auto device = kernel::devices::storage::ram_disk::device{module, 0, 0};
- REQUIRE(device.init());
-
- WHEN("reading a full block from the device")
- {
- auto buffer = std::vector<std::byte>(device.block_size());
- device.read_block(0, buffer.data());
-
- THEN("the buffer is filled with the module data")
- {
- REQUIRE_THAT(buffer, Catch::Matchers::RangeEquals(std::views::take(storage, device.block_size())));
- }
- }
-
- WHEN("reading from a block index beyond the module size")
- {
- auto buffer = std::vector<std::byte>(device.block_size());
- device.read_block(10, buffer.data());
-
- THEN("the buffer is filled with zeros")
- {
- REQUIRE_THAT(buffer, Catch::Matchers::RangeEquals(std::vector<std::byte>(device.block_size(), std::byte{0})));
- }
- }
-
- WHEN("reading into a null buffer")
- {
- REQUIRE_THROWS_AS(device.read_block(0, nullptr), std::runtime_error);
- }
-
- WHEN("writing to a full block")
- {
- auto buffer = std::vector<std::byte>(device.block_size(), std::byte{0x01});
- device.write_block(0, buffer.data());
-
- THEN("the module data is updated")
- {
- REQUIRE_THAT(std::views::take(storage, device.block_size()), Catch::Matchers::RangeEquals(buffer));
- }
- }
-
- WHEN("writing to a block index beyond the module size")
- {
- auto buffer = std::vector<std::byte>(device.block_size(), std::byte{0x01});
- device.write_block(10, buffer.data());
-
- THEN("the module data is not updated")
- {
- REQUIRE_THAT(storage, Catch::Matchers::RangeEquals(std::vector{4096, std::byte{0xff}}));
- }
- }
-
- WHEN("writing from a null buffer")
- {
- REQUIRE_THROWS_AS(device.write_block(0, nullptr), std::runtime_error);
- }
- }
-} \ No newline at end of file
diff --git a/kernel/src/filesystem/dentry.cpp b/kernel/src/filesystem/dentry.cpp
deleted file mode 100644
index 01de276c..00000000
--- a/kernel/src/filesystem/dentry.cpp
+++ /dev/null
@@ -1,95 +0,0 @@
-#include <kernel/filesystem/dentry.hpp>
-
-#include <kernel/filesystem/inode.hpp>
-
-#include <kapi/system.hpp>
-
-#include <kstd/memory>
-#include <kstd/string>
-
-#include <algorithm>
-#include <cstdint>
-#include <string_view>
-
-namespace kernel::filesystem
-{
- dentry::dentry(kstd::shared_ptr<dentry> const & parent, kstd::shared_ptr<inode> const & inode, std::string_view name)
- : m_name(name)
- , m_parent(parent)
- , m_inode(inode)
- , m_flags(0)
- {
- if (!m_inode)
- {
- kapi::system::panic("[FILESYSTEM] dentry constructed with null inode.");
- }
- if (m_name.empty())
- {
- kapi::system::panic("[FILESYSTEM] dentry constructed with empty name.");
- }
- }
-
- auto dentry::get_inode() const -> kstd::shared_ptr<inode> const &
- {
- return m_inode;
- }
-
- auto dentry::parent() const -> kstd::shared_ptr<dentry>
- {
- return m_parent.lock();
- }
-
- auto dentry::name() const -> std::string_view
- {
- return m_name;
- }
-
- auto dentry::absolute_path() const -> kstd::string
- {
- kstd::string path = m_name;
-
- auto parent = this->parent();
- while (parent)
- {
- auto parent_name = parent->m_name;
- if (parent_name == "/")
- {
- path = "/" + path;
- }
- else
- {
- path = parent_name + "/" + path;
- }
-
- parent = parent->parent();
- }
-
- return path;
- }
-
- auto dentry::add_child(kstd::shared_ptr<dentry> const & child) -> void
- {
- m_children.push_back(child);
- }
-
- auto dentry::find_child(std::string_view name) const -> kstd::shared_ptr<dentry>
- {
- auto it = std::ranges::find_if(m_children, [&](auto const & child) { return child->m_name == name; });
- return (it != m_children.end()) ? *it : nullptr;
- }
-
- auto dentry::set_flag(dentry_flags flag) -> void
- {
- m_flags |= static_cast<uint32_t>(flag);
- }
-
- auto dentry::unset_flag(dentry_flags flag) -> void
- {
- m_flags &= ~static_cast<uint32_t>(flag);
- }
-
- auto dentry::has_flag(dentry_flags flag) const -> bool
- {
- return (m_flags & static_cast<uint32_t>(flag)) != 0;
- }
-} // namespace kernel::filesystem \ No newline at end of file
diff --git a/kernel/src/filesystem/dentry.tests.cpp b/kernel/src/filesystem/dentry.tests.cpp
deleted file mode 100644
index b7690f57..00000000
--- a/kernel/src/filesystem/dentry.tests.cpp
+++ /dev/null
@@ -1,150 +0,0 @@
-#include <kernel/filesystem/dentry.hpp>
-
-#include <kernel/test_support/cpu.hpp>
-#include <kernel/test_support/filesystem/inode.hpp>
-
-#include <kstd/memory>
-#include <kstd/print>
-
-#include <catch2/catch_test_macros.hpp>
-
-SCENARIO("Dentry construction", "[filesystem][dentry]")
-{
- GIVEN("A parent dentry and inode")
- {
- auto inode = kstd::make_shared<kernel::tests::filesystem::inode>();
- auto parent_dentry = kstd::make_shared<kernel::filesystem::dentry>(nullptr, inode, "parent");
-
- WHEN("constructing a dentry")
- {
- auto child_dentry = kernel::filesystem::dentry{parent_dentry, inode, "child"};
-
- THEN("the dentry has the correct parent, inode, and name")
- {
- REQUIRE(child_dentry.parent() == parent_dentry);
- REQUIRE(child_dentry.get_inode() == inode);
- REQUIRE(child_dentry.name() == "child");
- }
-
- THEN("no flag is set")
- {
- REQUIRE_FALSE(child_dentry.has_flag(kernel::filesystem::dentry::dentry_flags::is_mount_point));
- }
- }
-
- WHEN("constructing a dentry with an empty name")
- {
- THEN("the dentry has the correct parent and inode, and an empty name")
- {
- REQUIRE_THROWS_AS((kernel::filesystem::dentry{parent_dentry, inode, ""}), kernel::tests::cpu::halt);
- }
- }
-
- WHEN("constructing a dentry with a null parent")
- {
- auto child_dentry = kernel::filesystem::dentry{nullptr, inode, "child"};
-
- THEN("the dentry has a null parent, the correct inode, and the correct name")
- {
- REQUIRE(child_dentry.parent() == nullptr);
- REQUIRE(child_dentry.get_inode() == inode);
- REQUIRE(child_dentry.name() == "child");
- }
-
- THEN("no flag is set")
- {
- REQUIRE_FALSE(child_dentry.has_flag(kernel::filesystem::dentry::dentry_flags::is_mount_point));
- }
- }
-
- WHEN("constructing a dentry with a null inode")
- {
- THEN("the system panics")
- {
- REQUIRE_THROWS_AS((kernel::filesystem::dentry{parent_dentry, nullptr, "child"}), kernel::tests::cpu::halt);
- }
- }
- }
-}
-
-SCENARIO("Dentry child logic", "[filesystem][dentry]")
-{
- GIVEN("A parent dentry and inode")
- {
- auto inode = kstd::make_shared<kernel::tests::filesystem::inode>();
- auto parent_dentry = kstd::make_shared<kernel::filesystem::dentry>(nullptr, inode, "parent");
-
- WHEN("adding child dentries")
- {
- auto child1 = kstd::make_shared<kernel::filesystem::dentry>(parent_dentry, inode, "child1");
- auto child2 = kstd::make_shared<kernel::filesystem::dentry>(parent_dentry, inode, "child2");
- parent_dentry->add_child(child1);
- parent_dentry->add_child(child2);
-
- THEN("the children can be found by name")
- {
- REQUIRE(parent_dentry->find_child("child1") == child1);
- REQUIRE(parent_dentry->find_child("child2") == child2);
- }
-
- THEN("finding a non-existent child returns null")
- {
- REQUIRE(parent_dentry->find_child("nonexistent") == nullptr);
- }
- }
- }
-}
-
-SCENARIO("Dentry Flag logic", "[filesystem][dentry]")
-{
- GIVEN("A dentry")
- {
- auto inode = kstd::make_shared<kernel::tests::filesystem::inode>();
- auto dentry = kernel::filesystem::dentry{nullptr, inode, "test"};
-
- WHEN("setting a flag")
- {
- dentry.set_flag(kernel::filesystem::dentry::dentry_flags::is_mount_point);
-
- THEN("the flag is set")
- {
- REQUIRE(dentry.has_flag(kernel::filesystem::dentry::dentry_flags::is_mount_point));
- }
- }
-
- WHEN("unsetting a flag")
- {
- dentry.set_flag(kernel::filesystem::dentry::dentry_flags::is_mount_point);
- dentry.unset_flag(kernel::filesystem::dentry::dentry_flags::is_mount_point);
-
- THEN("the flag is unset")
- {
- REQUIRE_FALSE(dentry.has_flag(kernel::filesystem::dentry::dentry_flags::is_mount_point));
- }
- }
- }
-}
-
-SCENARIO("Dentry path resolution", "[filesystem][dentry]")
-{
- GIVEN("A dentry with a parent hierarchy")
- {
- auto root_inode = kstd::make_shared<kernel::tests::filesystem::inode>();
- auto root_dentry = kstd::make_shared<kernel::filesystem::dentry>(nullptr, root_inode, "/");
-
- auto home_inode = kstd::make_shared<kernel::tests::filesystem::inode>();
- auto home_dentry = kstd::make_shared<kernel::filesystem::dentry>(root_dentry, home_inode, "home");
- root_dentry->add_child(home_dentry);
-
- auto user_inode = kstd::make_shared<kernel::tests::filesystem::inode>();
- auto user_dentry = kstd::make_shared<kernel::filesystem::dentry>(home_dentry, user_inode, "user");
- home_dentry->add_child(user_dentry);
-
- THEN("the full path is constructed correctly")
- {
- REQUIRE(root_dentry->absolute_path() == "/");
- REQUIRE(home_dentry->absolute_path() == "/home");
- REQUIRE(user_dentry->absolute_path() == "/home/user");
- }
- }
-} \ No newline at end of file
diff --git a/kernel/src/filesystem/devfs/filesystem.cpp b/kernel/src/filesystem/devfs/filesystem.cpp
deleted file mode 100644
index ce887ff3..00000000
--- a/kernel/src/filesystem/devfs/filesystem.cpp
+++ /dev/null
@@ -1,81 +0,0 @@
-#include <kernel/filesystem/devfs/filesystem.hpp>
-
-#include "kernel/filesystem/filesystem.hpp"
-#include <kernel/devices/storage/management.hpp>
-#include <kernel/filesystem/devfs/inode.hpp>
-#include <kernel/filesystem/device_inode.hpp>
-#include <kernel/filesystem/inode.hpp>
-#include <kernel/filesystem/type.hpp>
-
-#include <kapi/devices/device.hpp>
-
-#include <kstd/memory>
-
-#include <algorithm>
-#include <string_view>
-
-namespace kernel::filesystem::devfs
-{
- struct type final : kernel::filesystem::type
- {
- [[nodiscard]] auto name() const noexcept -> std::string_view override
- {
- return "devfs";
- }
-
- [[nodiscard]] auto requires_device() const noexcept -> bool override
- {
- return false;
- }
-
- [[nodiscard]] auto make_instance() const -> kstd::shared_ptr<kernel::filesystem::filesystem> override
- {
- return kstd::make_shared<filesystem>();
- }
- };
-
- [[gnu::used]]
- constexpr auto registration = type_registration<type>{};
-
- auto filesystem::mount(kstd::shared_ptr<kernel::filesystem::inode> const &) -> operation_result
- {
- m_root_inode = kstd::make_shared<inode>();
- build_device_inode_table();
-
- return operation_result::success;
- }
-
- auto filesystem::lookup(kstd::shared_ptr<kernel::filesystem::inode> const & parent, std::string_view name) const
- -> kstd::shared_ptr<kernel::filesystem::inode>
- {
- if (!parent || !parent->is_directory())
- {
- return nullptr;
- }
-
- if (parent.get() != m_root_inode.get())
- {
- return nullptr;
- }
-
- auto it = std::ranges::find_if(m_inodes, [&](auto const & dev_node) {
- if (auto device_inode_ptr = static_cast<device_inode *>(dev_node.get()))
- {
- return device_inode_ptr->device()->name() == name;
- }
- return false;
- });
- return (it != m_inodes.end()) ? *it : nullptr;
- }
-
- auto filesystem::build_device_inode_table() -> void
- {
- m_inodes.clear();
-
- auto storage_mgmt = devices::storage::management::get();
- std::ranges::for_each(storage_mgmt.all_controllers(), [&](auto const & controller) {
- std::ranges::for_each(controller->all_devices(),
- [&](auto const & device) { m_inodes.push_back(kstd::make_shared<device_inode>(device)); });
- });
- }
-} // namespace kernel::filesystem::devfs \ No newline at end of file
diff --git a/kernel/src/filesystem/devfs/filesystem.tests.cpp b/kernel/src/filesystem/devfs/filesystem.tests.cpp
deleted file mode 100644
index 36cb4117..00000000
--- a/kernel/src/filesystem/devfs/filesystem.tests.cpp
+++ /dev/null
@@ -1,72 +0,0 @@
-#include <kernel/filesystem/devfs/filesystem.hpp>
-
-#include <kernel/filesystem/filesystem.hpp>
-#include <kernel/test_support/filesystem/storage_boot_module_fixture.hpp>
-
-#include <catch2/catch_test_macros.hpp>
-
-SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_fixture,
- "Devfs filesystem lookup uses storage management devices", "[filesystem][devfs][filesystem]")
-{
- GIVEN("a boot module registry with one module")
- {
- setup_modules(1);
-
- auto fs = kernel::filesystem::devfs::filesystem{};
- auto result = fs.mount(nullptr);
-
- THEN("mount succeeds")
- {
- REQUIRE(result == kernel::filesystem::filesystem::operation_result::success);
- REQUIRE(fs.root_inode() != nullptr);
- }
-
- THEN("lookup on root finds ram0 device inode")
- {
- auto inode = fs.lookup(fs.root_inode(), "ram0");
- REQUIRE(inode != nullptr);
- REQUIRE(inode->is_device());
- }
-
- THEN("lookup of an unknown device returns null")
- {
- auto inode = fs.lookup(fs.root_inode(), "ram99");
- REQUIRE(inode == nullptr);
- }
-
- THEN("lookup with wrong parent returns null")
- {
- auto other_fs = kernel::filesystem::devfs::filesystem{};
- other_fs.mount(nullptr);
-
- auto inode = fs.lookup(other_fs.root_inode(), "ram0");
- REQUIRE(inode == nullptr);
- }
-
- THEN("lookup with a non-directory parent returns null")
- {
- auto non_directory_inode = fs.lookup(fs.root_inode(), "ram0");
- REQUIRE(non_directory_inode != nullptr);
- REQUIRE_FALSE(non_directory_inode->is_directory());
-
- auto result = fs.lookup(non_directory_inode, "anything");
- REQUIRE(result == nullptr);
- }
- }
-
- GIVEN("a boot module registry with three modules")
- {
- setup_modules(3, 2048);
-
- auto fs = kernel::filesystem::devfs::filesystem{};
- auto result = fs.mount(nullptr);
- REQUIRE(result == kernel::filesystem::filesystem::operation_result::success);
-
- THEN("lookup finds all generated RAM devices")
- {
- REQUIRE(fs.lookup(fs.root_inode(), "ram0") != nullptr);
- REQUIRE(fs.lookup(fs.root_inode(), "ram16") != nullptr);
- REQUIRE(fs.lookup(fs.root_inode(), "ram32") != nullptr);
- }
- }
-}
diff --git a/kernel/src/filesystem/devfs/inode.cpp b/kernel/src/filesystem/devfs/inode.cpp
deleted file mode 100644
index 7bbfbbed..00000000
--- a/kernel/src/filesystem/devfs/inode.cpp
+++ /dev/null
@@ -1,21 +0,0 @@
-#include <kernel/filesystem/devfs/inode.hpp>
-
-#include <cstddef>
-
-namespace kernel::filesystem::devfs
-{
- auto inode::read(void *, size_t, size_t) const -> size_t
- {
- return 0;
- }
-
- auto inode::write(void const *, size_t, size_t) -> size_t
- {
- return 0;
- }
-
- auto inode::is_directory() const -> bool
- {
- return true;
- }
-} // namespace kernel::filesystem::devfs \ No newline at end of file
diff --git a/kernel/src/filesystem/devfs/inode.tests.cpp b/kernel/src/filesystem/devfs/inode.tests.cpp
deleted file mode 100644
index ae26e742..00000000
--- a/kernel/src/filesystem/devfs/inode.tests.cpp
+++ /dev/null
@@ -1,55 +0,0 @@
-#include <kernel/filesystem/devfs/inode.hpp>
-
-#include <kstd/memory>
-#include <kstd/print>
-#include <kstd/vector>
-
-#include <catch2/catch_test_macros.hpp>
-
-#include <cstdint>
-
-SCENARIO("Devfs inode creation", "[filesystem][devfs][inode]")
-{
- GIVEN("a devfs inode")
- {
- auto inode = kernel::filesystem::devfs::inode{};
-
- THEN("the inode has the correct kind")
- {
- REQUIRE(inode.is_directory());
- REQUIRE_FALSE(inode.is_device());
- REQUIRE_FALSE(inode.is_regular());
- REQUIRE_FALSE(inode.is_symbolic_link());
- }
- }
-}
-
-SCENARIO("Devfs inode read/write", "[filesystem][devfs][inode]")
-{
- GIVEN("a devfs inode")
- {
- auto inode = kernel::filesystem::devfs::inode{};
-
- WHEN("attempting to read from the devfs inode")
- {
- kstd::vector<uint8_t> buffer(512);
- auto bytes_read = inode.read(buffer.data(), 0, buffer.size());
-
- THEN("no bytes are read")
- {
- REQUIRE(bytes_read == 0);
- }
- }
-
- WHEN("attempting to write to the devfs inode")
- {
- kstd::vector<uint8_t> buffer(512);
- auto bytes_written = inode.write(buffer.data(), 0, buffer.size());
-
- THEN("no bytes are written")
- {
- REQUIRE(bytes_written == 0);
- }
- }
- }
-}
diff --git a/kernel/src/filesystem/device_inode.cpp b/kernel/src/filesystem/device_inode.cpp
deleted file mode 100644
index 81a784cd..00000000
--- a/kernel/src/filesystem/device_inode.cpp
+++ /dev/null
@@ -1,57 +0,0 @@
-#include <kernel/filesystem/device_inode.hpp>
-
-#include <kernel/devices/block_device_utils.hpp>
-
-#include <kapi/devices/device.hpp>
-#include <kapi/system.hpp>
-
-#include <kstd/memory>
-
-#include <cstddef>
-
-namespace kernel::filesystem
-{
- device_inode::device_inode(kstd::shared_ptr<kapi::devices::device> const & device)
- : m_device(device)
- {
- if (!device)
- {
- kapi::system::panic("[FILESYSTEM] device_inode constructed with null device.");
- }
- }
-
- auto device_inode::read(void * buffer, size_t offset, size_t size) const -> size_t
- {
- if (m_device->is_block_device())
- {
- return devices::block_device_utils::read(m_device, buffer, offset, size);
- }
- else
- {
- kapi::system::panic("[FILESYSTEM] device_file::read called on non-block device.");
- }
- }
-
- auto device_inode::write(void const * buffer, size_t offset, size_t size) -> size_t
- {
- if (m_device->is_block_device())
- {
- return devices::block_device_utils::write(m_device, buffer, offset, size);
- }
- else
- {
- kapi::system::panic("[FILESYSTEM] device_file::write called on non-block device.");
- }
- }
-
- auto device_inode::device() const -> kstd::shared_ptr<kapi::devices::device> const &
- {
- return m_device;
- }
-
- auto device_inode::is_device() const -> bool
- {
- return true;
- }
-
-} // namespace kernel::filesystem \ No newline at end of file
diff --git a/kernel/src/filesystem/device_inode.tests.cpp b/kernel/src/filesystem/device_inode.tests.cpp
deleted file mode 100644
index 025a22a2..00000000
--- a/kernel/src/filesystem/device_inode.tests.cpp
+++ /dev/null
@@ -1,109 +0,0 @@
-#include <kernel/filesystem/device_inode.hpp>
-
-#include <kernel/test_support/cpu.hpp>
-#include <kernel/test_support/devices/block_device.hpp>
-#include <kernel/test_support/devices/character_device.hpp>
-
-#include <kstd/memory>
-#include <kstd/print>
-#include <kstd/vector>
-
-#include <catch2/catch_test_macros.hpp>
-
-#include <cstddef>
-#include <cstdint>
-
-SCENARIO("Device inode construction", "[filesystem][device_inode]")
-{
- GIVEN("a block device")
- {
- auto device = kstd::make_shared<kernel::tests::devices::block_device>(0, 0, "test_block_device", 512, 3 * 512);
-
- WHEN("constructing a device inode with the block device")
- {
- auto inode = kernel::filesystem::device_inode{device};
-
- THEN("the device inode has the correct device")
- {
- REQUIRE(inode.device() == device);
- }
-
- THEN("the device inode has the correct kind")
- {
- REQUIRE(inode.is_device());
- REQUIRE_FALSE(inode.is_directory());
- REQUIRE_FALSE(inode.is_regular());
- REQUIRE_FALSE(inode.is_symbolic_link());
- }
- }
-
- WHEN("constructing a device inode with a null device")
- {
- THEN("the constructor panics")
- {
- REQUIRE_THROWS_AS((kernel::filesystem::device_inode{nullptr}), kernel::tests::cpu::halt);
- }
- }
- }
-}
-
-SCENARIO("Device inode read/write", "[filesystem][device_inode]")
-{
- GIVEN("a block device and a device inode for that device")
- {
- auto device = kstd::make_shared<kernel::tests::devices::block_device>(0, 0, "test_block_device", 512, 3 * 512);
- auto inode = kernel::filesystem::device_inode{device};
-
- WHEN("writing to the device inode")
- {
- kstd::vector<uint8_t> write_buffer(1024);
- for (size_t i = 0; i < write_buffer.size(); ++i)
- {
- write_buffer[i] = static_cast<uint8_t>(i % 256);
- }
-
- auto bytes_written = inode.write(write_buffer.data(), 256, write_buffer.size());
-
- THEN("the correct number of bytes is written")
- {
- REQUIRE(bytes_written == 1024);
- }
-
- THEN("the data written matches the data read back from the device inode")
- {
- kstd::vector<uint8_t> read_buffer(1024);
- auto bytes_read = inode.read(read_buffer.data(), 256, read_buffer.size());
-
- REQUIRE(bytes_read == write_buffer.size());
- REQUIRE(read_buffer == write_buffer);
- }
- }
- }
-}
-
-SCENARIO("Device inode read/write with a non-block device", "[filesystem][device_inode]")
-{
- GIVEN("a non-block device and a device inode for that device")
- {
- auto device = kstd::make_shared<kernel::tests::devices::character_device>(0, 0, "test_character_device");
- auto inode = kernel::filesystem::device_inode{device};
-
- WHEN("reading from the device inode")
- {
- kstd::vector<uint8_t> read_buffer(512);
- THEN("the system panics")
- {
- REQUIRE_THROWS_AS(inode.read(read_buffer.data(), 0, read_buffer.size()), kernel::tests::cpu::halt);
- }
- }
-
- WHEN("writing to the device inode")
- {
- kstd::vector<uint8_t> write_buffer(512);
- THEN("the system panics")
- {
- REQUIRE_THROWS_AS(inode.write(write_buffer.data(), 0, write_buffer.size()), kernel::tests::cpu::halt);
- }
- }
- }
-}
diff --git a/kernel/src/filesystem/ext2/filesystem.cpp b/kernel/src/filesystem/ext2/filesystem.cpp
deleted file mode 100644
index 3180a19a..00000000
--- a/kernel/src/filesystem/ext2/filesystem.cpp
+++ /dev/null
@@ -1,247 +0,0 @@
-#include <kernel/filesystem/ext2/filesystem.hpp>
-
-#include <kernel/filesystem/ext2/block_group_descriptor.hpp>
-#include <kernel/filesystem/ext2/inode.hpp>
-#include <kernel/filesystem/ext2/linked_directory_entry.hpp>
-#include <kernel/filesystem/ext2/superblock.hpp>
-#include <kernel/filesystem/filesystem.hpp>
-#include <kernel/filesystem/inode.hpp>
-#include <kernel/filesystem/type.hpp>
-
-#include <kstd/memory>
-#include <kstd/unikstd.h>
-#include <kstd/vector>
-
-#include <array>
-#include <cstddef>
-#include <cstdint>
-#include <string_view>
-
-namespace kernel::filesystem::ext2
-{
-
- struct type final : kernel::filesystem::type
- {
- [[nodiscard]] auto name() const noexcept -> std::string_view override
- {
- return "ext2";
- }
-
- [[nodiscard]] auto requires_device() const noexcept -> bool override
- {
- return true;
- }
-
- [[nodiscard]] auto make_instance() const -> kstd::shared_ptr<kernel::filesystem::filesystem> override
- {
- return kstd::make_shared<filesystem>();
- }
- };
-
- [[gnu::used]]
- constexpr auto registration = type_registration<type>{};
-
- auto filesystem::mount(kstd::shared_ptr<kernel::filesystem::inode> const & backing_inode) -> operation_result
- {
- kernel::filesystem::filesystem::mount(backing_inode);
-
- m_backing_inode->read(&m_superblock, constants::superblock_offset, sizeof(m_superblock));
-
- if (m_superblock.magic != constants::magic_number)
- {
- return operation_result::invalid_magic_number;
- }
-
- auto const blocks_per_group = m_superblock.blocks_per_group;
- auto const num_block_groups = (m_superblock.blocks_count + blocks_per_group - 1) / blocks_per_group;
-
- m_block_group_descriptors = kstd::vector<block_group_descriptor>(num_block_groups);
-
- m_backing_inode->read(m_block_group_descriptors.data(), block_group_descriptor_table_offset(),
- num_block_groups * sizeof(block_group_descriptor));
-
- m_root_inode = read_inode(constants::root_inode_number);
-
- if (!m_root_inode || !m_root_inode->is_directory())
- {
- return operation_result::invalid_root_inode;
- }
- return operation_result::success;
- }
-
- auto filesystem::lookup(kstd::shared_ptr<kernel::filesystem::inode> const & parent, std::string_view name) const
- -> kstd::shared_ptr<kernel::filesystem::inode>
- {
- if (!parent || !parent->is_directory())
- {
- return nullptr;
- }
-
- auto * ext2_parent = static_cast<inode *>(parent.get());
- if (!ext2_parent)
- {
- return nullptr;
- }
-
- auto const & inode_data = ext2_parent->data();
- kstd::vector<uint8_t> buffer(block_size());
-
- for (uint32_t i = 0; i < inode_block_count(inode_data); ++i)
- {
- auto const global_block_number = map_inode_block_index_to_global_block_number(i, inode_data);
- auto const block_offset = global_block_number * block_size();
- m_backing_inode->read(buffer.data(), block_offset, block_size());
-
- auto const * entry = reinterpret_cast<linked_directory_entry const *>(buffer.data());
- auto bytes_read = 0uz;
-
- while (bytes_read < block_size() && entry->inode != 0)
- {
- auto const entry_name = std::string_view{entry->name.data(), entry->name_len};
- if (entry_name == name)
- {
- return read_inode(entry->inode);
- }
-
- bytes_read += entry->rec_len;
- entry = reinterpret_cast<linked_directory_entry const *>(buffer.data() + bytes_read);
- }
- }
-
- return nullptr;
- }
-
- auto filesystem::read_inode(uint32_t inode_number) const -> kstd::shared_ptr<inode>
- {
- auto const inodes_per_group = m_superblock.inodes_per_group;
- auto const block_group_index = (inode_number - 1) / inodes_per_group;
- auto const inode_index_within_group = (inode_number - 1) % inodes_per_group;
-
- if (block_group_index >= m_block_group_descriptors.size())
- {
- return nullptr;
- }
-
- auto const & block_group_descriptor = m_block_group_descriptors.at(block_group_index);
- auto const inode_table_start_block = block_group_descriptor.inode_table;
- auto const inode_table_offset = static_cast<size_t>(inode_table_start_block) * block_size();
- auto const inode_offset = inode_table_offset + inode_index_within_group * inode_size();
-
- auto new_inode_data = inode_data{};
- m_backing_inode->read(&new_inode_data, inode_offset, sizeof(inode_data));
-
- return kstd::make_shared<inode>(this, new_inode_data);
- }
-
- auto filesystem::indirect_levels() const -> std::array<indirect_level, 3>
- {
- return {
- {{constants::singly_indirect_block_index, block_numbers_per_singly_indirect_block()},
- {constants::doubly_indirect_block_index, block_numbers_per_doubly_indirect_block()},
- {constants::triply_indirect_block_index, block_numbers_per_triply_indirect_block()}}
- };
- }
-
- auto filesystem::map_inode_block_index_to_global_block_number(size_t inode_block_index, inode_data data) const
- -> kstd::ssize_t
- {
- if (inode_block_index < constants::direct_block_count)
- {
- return data.block.at(inode_block_index);
- }
-
- inode_block_index -= constants::direct_block_count;
-
- for (auto const & level : indirect_levels())
- {
- if (inode_block_index >= level.capacity)
- {
- inode_block_index -= level.capacity;
- continue;
- }
-
- auto block_number = data.block[level.slot_index];
- if (block_number == 0)
- {
- return 0;
- }
-
- for (auto stride = level.capacity / block_numbers_per_block();; stride /= block_numbers_per_block())
- {
- auto const idx = inode_block_index / stride;
- inode_block_index %= stride;
-
- block_number = read_block_number_at_index(block_number, idx);
- if (block_number == 0)
- {
- return 0;
- }
-
- if (stride == 1)
- {
- break;
- }
- }
-
- return block_number;
- }
-
- return -1;
- }
-
- auto filesystem::read_block_number_at_index(uint32_t block_number, size_t index) const -> uint32_t
- {
- uint32_t block_number_buffer = 0;
-
- auto const block_start_offset = block_number * block_size();
- auto const number_start_address = block_start_offset + index * sizeof(uint32_t);
- m_backing_inode->read(&block_number_buffer, number_start_address, sizeof(uint32_t));
-
- return block_number_buffer;
- }
-
- auto filesystem::block_numbers_per_block() const -> size_t
- {
- return block_size() / sizeof(uint32_t);
- }
-
- auto filesystem::block_numbers_per_singly_indirect_block() const -> size_t
- {
- return block_numbers_per_block();
- }
-
- auto filesystem::block_numbers_per_doubly_indirect_block() const -> size_t
- {
- return block_numbers_per_singly_indirect_block() * block_numbers_per_block();
- }
-
- auto filesystem::block_numbers_per_triply_indirect_block() const -> size_t
- {
- return block_numbers_per_doubly_indirect_block() * block_numbers_per_block();
- }
-
- auto filesystem::block_size() const -> size_t
- {
- return constants::base_block_size << m_superblock.log_block_size;
- }
-
- auto filesystem::revision_level() const -> uint32_t
- {
- return m_superblock.rev_level;
- }
-
- auto filesystem::inode_size() const -> uint16_t
- {
- return revision_level() == constants::good_old_revision ? 128 : m_superblock.inode_size;
- }
-
- auto filesystem::inode_block_count(inode_data const & data) const -> uint32_t
- {
- return data.blocks / (2 << m_superblock.log_block_size);
- }
-
- auto filesystem::block_group_descriptor_table_offset() const -> size_t
- {
- return block_size() == 1024 ? 2 * block_size() : block_size();
- }
-} // namespace kernel::filesystem::ext2
diff --git a/kernel/src/filesystem/ext2/filesystem.tests.cpp b/kernel/src/filesystem/ext2/filesystem.tests.cpp
deleted file mode 100644
index 83410702..00000000
--- a/kernel/src/filesystem/ext2/filesystem.tests.cpp
+++ /dev/null
@@ -1,139 +0,0 @@
-#include <kernel/filesystem/ext2/filesystem.hpp>
-
-#include <kernel/devices/storage/management.hpp>
-#include <kernel/filesystem/device_inode.hpp>
-#include <kernel/filesystem/ext2/inode.hpp>
-#include <kernel/filesystem/filesystem.hpp>
-#include <kernel/test_support/devices/block_device.hpp>
-#include <kernel/test_support/filesystem/ext2.hpp>
-#include <kernel/test_support/filesystem/storage_boot_module_fixture.hpp>
-
-#include <kstd/memory>
-#include <kstd/vector>
-
-#include <catch2/catch_test_macros.hpp>
-
-#include <array>
-#include <cstdint>
-#include <filesystem>
-
-SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_fixture,
- "Ext2 filesystem mount and lookup with real image", "[filesystem][ext2][filesystem][img]")
-{
- auto const image_path = std::filesystem::path{KERNEL_TEST_ASSETS_DIR} / "ext2_1KB_fs.img";
-
- GIVEN("a mounted ext2 filesystem from a real image")
- {
- REQUIRE(std::filesystem::exists(image_path));
- REQUIRE_NOTHROW(setup_modules_from_img({"test_img_module"}, {image_path}));
-
- auto boot_device = kernel::devices::storage::management::get().determine_boot_device();
- REQUIRE(boot_device != nullptr);
-
- auto dev_inode = kstd::make_shared<kernel::filesystem::device_inode>(boot_device);
-
- auto fs = kernel::filesystem::ext2::filesystem{};
- REQUIRE(fs.mount(dev_inode) == kernel::filesystem::filesystem::operation_result::success);
-
- THEN("the root inode is available and is a directory")
- {
- REQUIRE(fs.root_inode() != nullptr);
- REQUIRE(fs.root_inode()->is_directory());
- }
-
- THEN("lookup resolves known entries from the image")
- {
- auto information = fs.lookup(fs.root_inode(), "information");
- REQUIRE(information != nullptr);
- REQUIRE(information->is_directory());
-
- auto info_1 = fs.lookup(information, "info_1.txt");
- REQUIRE(info_1 != nullptr);
- REQUIRE(info_1->is_regular());
- }
-
- THEN("lookup returns null for invalid inputs")
- {
- REQUIRE(fs.lookup(nullptr, "information") == nullptr);
-
- auto information = fs.lookup(fs.root_inode(), "information");
- REQUIRE(information != nullptr);
- auto info_1 = fs.lookup(information, "info_1.txt");
- REQUIRE(info_1 != nullptr);
-
- REQUIRE(fs.lookup(info_1, "anything") == nullptr);
- REQUIRE(fs.lookup(fs.root_inode(), "does_not_exist") == nullptr);
- }
- }
-}
-
-SCENARIO("Ext2 filesystem rejects invalid magic", "[filesystem][ext2][filesystem]")
-{
- auto const block_size = 1024;
- GIVEN("a block device that does not contain an ext2 superblock")
- {
- auto device = kstd::make_shared<kernel::tests::devices::block_device>(0, 0, "mock", block_size, 2 * block_size);
- REQUIRE(device != nullptr);
-
- auto dev_inode = kstd::make_shared<kernel::filesystem::device_inode>(device);
-
- auto fs = kernel::filesystem::ext2::filesystem{};
-
- THEN("mount fails with invalid_magic_number")
- {
- REQUIRE(fs.mount(dev_inode) == kernel::filesystem::filesystem::operation_result::invalid_magic_number);
- }
- }
-}
-
-SCENARIO("Ext2 block mapping includes direct and all indirect levels", "[filesystem][ext2][filesystem]")
-{
- auto const block_size = 1024;
-
- GIVEN("a minimally valid ext2 layout with configured indirect block tables")
- {
- auto device = kstd::make_shared<kernel::tests::devices::block_device>(0, 0, "mock", block_size, 128 * block_size);
- REQUIRE(device != nullptr);
-
- kernel::tests::filesystem::ext2::setup_mock_ext2_layout(*device);
-
- auto dev_inode = kstd::make_shared<kernel::filesystem::device_inode>(device);
-
- auto fs = kernel::filesystem::ext2::filesystem{};
- REQUIRE(fs.mount(dev_inode) == kernel::filesystem::filesystem::operation_result::success);
-
- auto inode_data = kernel::filesystem::ext2::inode_data{};
- inode_data.block[0] = 7;
-
- inode_data.block[12] = 30;
- kernel::tests::filesystem::ext2::write_u32(*device, 30 * block_size, 31);
-
- inode_data.block[13] = 40;
- kernel::tests::filesystem::ext2::write_u32(*device, 40 * block_size, 41);
- kernel::tests::filesystem::ext2::write_u32(*device, 41 * block_size, 42);
-
- inode_data.block[14] = 50;
- kernel::tests::filesystem::ext2::write_u32(*device, 50 * block_size, 51);
- kernel::tests::filesystem::ext2::write_u32(*device, 51 * block_size, 52);
- kernel::tests::filesystem::ext2::write_u32(*device, 52 * block_size, 53);
-
- auto const numbers_per_block = static_cast<uint32_t>(block_size / sizeof(uint32_t));
- auto const singly_start = static_cast<uint32_t>(kernel::filesystem::ext2::constants::direct_block_count);
- auto const doubly_start = singly_start + numbers_per_block;
- auto const triply_start = doubly_start + numbers_per_block * numbers_per_block;
-
- THEN("mapping resolves direct, singly, doubly and triply indirect indexes")
- {
- REQUIRE(fs.map_inode_block_index_to_global_block_number(0, inode_data) == 7);
- REQUIRE(fs.map_inode_block_index_to_global_block_number(singly_start, inode_data) == 31);
- REQUIRE(fs.map_inode_block_index_to_global_block_number(doubly_start, inode_data) == 42);
- REQUIRE(fs.map_inode_block_index_to_global_block_number(triply_start, inode_data) == 53);
- }
-
- THEN("mapping returns zero for out-of-range indexes")
- {
- auto const beyond_triply = triply_start + numbers_per_block * numbers_per_block * numbers_per_block;
- REQUIRE(fs.map_inode_block_index_to_global_block_number(beyond_triply, inode_data) == -1);
- }
- }
-}
diff --git a/kernel/src/filesystem/ext2/inode.cpp b/kernel/src/filesystem/ext2/inode.cpp
deleted file mode 100644
index 35a32ee4..00000000
--- a/kernel/src/filesystem/ext2/inode.cpp
+++ /dev/null
@@ -1,111 +0,0 @@
-#include <kernel/filesystem/ext2/inode.hpp>
-
-#include <kernel/filesystem/ext2/filesystem.hpp>
-#include <kernel/filesystem/inode.hpp>
-
-#include <kapi/system.hpp>
-
-#include <kstd/cstring>
-
-#include <algorithm>
-#include <cstddef>
-#include <cstdint>
-
-namespace kernel::filesystem::ext2
-{
- inode::inode(filesystem const * fs, inode_data const & data)
- : m_filesystem(fs)
- , m_data(data)
- {
- if (!m_filesystem)
- {
- kapi::system::panic("[EXT2] ext2::inode constructed with filesystem null pointer");
- }
- }
-
- auto inode::read(void * buffer, size_t offset, size_t size) const -> size_t
- {
- auto const max_readable = this->size() - offset;
- auto const requested_size = std::min(size, max_readable);
-
- if (is_symbolic_link() && this->size() <= sizeof(m_data.block))
- {
- auto inline_target = reinterpret_cast<uint8_t const *>(m_data.block.data());
- kstd::libc::memcpy(static_cast<uint8_t *>(buffer), inline_target + offset, requested_size);
- return requested_size;
- }
-
- auto block_index = offset / m_filesystem->block_size();
- auto in_block_offset = offset % m_filesystem->block_size();
-
- auto bytes_read = 0uz;
-
- while (bytes_read < requested_size)
- {
- auto const block_number = m_filesystem->map_inode_block_index_to_global_block_number(block_index, m_data);
- if (block_number == -1)
- {
- break;
- }
-
- auto const bytes_to_read = std::min(requested_size - bytes_read, m_filesystem->block_size() - in_block_offset);
- if (block_number == 0)
- {
- kstd::libc::memset(static_cast<uint8_t *>(buffer) + bytes_read, 0, bytes_to_read);
- bytes_read += bytes_to_read;
- }
- else
- {
- auto const block_start_offset = block_number * m_filesystem->block_size();
- auto const read_offset = block_start_offset + in_block_offset;
-
- bytes_read += m_filesystem->backing_inode()->read(static_cast<uint8_t *>(buffer) + bytes_read, read_offset,
- bytes_to_read);
- }
-
- block_index++;
- in_block_offset = 0; // After the first block, we always start at the beginning of the block
- }
-
- return bytes_read;
- }
-
- auto inode::write(void const *, size_t, size_t) -> size_t
- {
- kapi::system::panic("[EXT2] inode::write is not implemented yet");
- return 0;
- }
-
- [[nodiscard]] auto inode::data() const -> inode_data const &
- {
- return m_data;
- }
-
- auto inode::is_regular() const -> bool
- {
- return (m_data.mode & constants::mode_mask) == constants::mode_regular;
- }
-
- auto inode::is_directory() const -> bool
- {
- return (m_data.mode & constants::mode_mask) == constants::mode_directory;
- }
-
- auto inode::is_symbolic_link() const -> bool
- {
- return (m_data.mode & constants::mode_mask) == constants::mode_symbolic_link;
- }
-
- auto inode::size() const -> uint64_t
- {
- uint64_t size = m_data.size;
-
- if (m_filesystem->revision_level() > constants::good_old_revision && is_regular())
- {
- size |= static_cast<uint64_t>(m_data.dir_acl) << 32;
- }
-
- return size;
- }
-
-} // namespace kernel::filesystem::ext2
diff --git a/kernel/src/filesystem/ext2/inode.tests.cpp b/kernel/src/filesystem/ext2/inode.tests.cpp
deleted file mode 100644
index 4aecc04a..00000000
--- a/kernel/src/filesystem/ext2/inode.tests.cpp
+++ /dev/null
@@ -1,376 +0,0 @@
-#include <kernel/filesystem/ext2/inode.hpp>
-
-#include <kernel/devices/storage/management.hpp>
-#include <kernel/filesystem/device_inode.hpp>
-#include <kernel/filesystem/ext2/filesystem.hpp>
-#include <kernel/filesystem/ext2/superblock.hpp>
-#include <kernel/filesystem/filesystem.hpp>
-#include <kernel/test_support/cpu.hpp>
-#include <kernel/test_support/devices/block_device.hpp>
-#include <kernel/test_support/filesystem/ext2.hpp>
-#include <kernel/test_support/filesystem/storage_boot_module_fixture.hpp>
-
-#include <kstd/memory>
-#include <kstd/vector>
-
-#include <catch2/catch_test_macros.hpp>
-
-#include <algorithm>
-#include <cstddef>
-#include <filesystem>
-#include <string_view>
-
-SCENARIO("Ext2 inode initialization and properties", "[filesystem][ext2][inode]")
-{
- GIVEN("an ext2 filesystem")
- {
- auto fs = kernel::filesystem::ext2::filesystem{};
- auto data = kernel::filesystem::ext2::inode_data{};
-
- THEN("the inode is initialized with regular file mode in data and has the kind regular")
- {
- data.mode = kernel::filesystem::ext2::constants::mode_regular;
- auto inode = kernel::filesystem::ext2::inode(&fs, data);
-
- REQUIRE(inode.is_regular());
- REQUIRE_FALSE(inode.is_directory());
- REQUIRE_FALSE(inode.is_device());
- REQUIRE_FALSE(inode.is_symbolic_link());
- }
-
- THEN("the inode is initialized with directory mode in data and has the kind directory")
- {
- data.mode = kernel::filesystem::ext2::constants::mode_directory;
- auto inode = kernel::filesystem::ext2::inode(&fs, data);
-
- REQUIRE_FALSE(inode.is_regular());
- REQUIRE(inode.is_directory());
- REQUIRE_FALSE(inode.is_device());
- REQUIRE_FALSE(inode.is_symbolic_link());
- }
-
- THEN("the inode is initialized with symbolic link mode in data and has the kind symbolic link")
- {
- data.mode = kernel::filesystem::ext2::constants::mode_symbolic_link;
- auto inode = kernel::filesystem::ext2::inode(&fs, data);
-
- REQUIRE_FALSE(inode.is_regular());
- REQUIRE_FALSE(inode.is_directory());
- REQUIRE_FALSE(inode.is_device());
- REQUIRE(inode.is_symbolic_link());
- }
-
- THEN("the inode is initialized with zero mode in data and has no specific kind")
- {
- data.mode = 0;
- auto inode = kernel::filesystem::ext2::inode(&fs, data);
-
- REQUIRE_FALSE(inode.is_regular());
- REQUIRE_FALSE(inode.is_directory());
- REQUIRE_FALSE(inode.is_device());
- REQUIRE_FALSE(inode.is_symbolic_link());
- }
- }
-
- GIVEN("no filesystem (null pointer)")
- {
- THEN("constructing an inode with a null filesystem pointer panics")
- {
- REQUIRE_THROWS_AS(kernel::filesystem::ext2::inode(nullptr, {}), kernel::tests::cpu::halt);
- }
- }
-}
-
-SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_fixture, "Ext2 inode reads from real image",
- "[filesystem][ext2][inode][img]")
-{
- auto const image_path = std::filesystem::path{KERNEL_TEST_ASSETS_DIR} / "ext2_1KB_fs.img";
-
- GIVEN("a mounted ext2 filesystem and a regular file inode")
- {
- REQUIRE(std::filesystem::exists(image_path));
- REQUIRE_NOTHROW(setup_modules_from_img({"test_img_module"}, {image_path}));
-
- auto boot_device = kernel::devices::storage::management::get().determine_boot_device();
- REQUIRE(boot_device != nullptr);
-
- auto dev_inode = kstd::make_shared<kernel::filesystem::device_inode>(boot_device);
-
- auto fs = kernel::filesystem::ext2::filesystem{};
- REQUIRE(fs.mount(dev_inode) == kernel::filesystem::filesystem::operation_result::success);
-
- auto information = fs.lookup(fs.root_inode(), "information");
- REQUIRE(information != nullptr);
- auto file = fs.lookup(information, "info_1.txt");
- REQUIRE(file != nullptr);
- REQUIRE(file->is_regular());
-
- THEN("reading from offset zero returns expected file prefix")
- {
- auto buffer = kstd::vector<std::byte>(6);
- auto const bytes_read = file->read(buffer.data(), 0, buffer.size());
-
- REQUIRE(bytes_read == 6);
-
- auto const text = std::string_view{reinterpret_cast<char const *>(buffer.data()), bytes_read};
- REQUIRE(text == "info_1");
- }
-
- THEN("reading with an offset returns the expected byte")
- {
- auto buffer = kstd::vector<std::byte>(1);
- auto const bytes_read = file->read(buffer.data(), 5, buffer.size());
-
- REQUIRE(bytes_read == 1);
- REQUIRE(static_cast<char>(buffer[0]) == '1');
- }
- }
-}
-
-SCENARIO("Ext2 inode handles zeros in block mappings as file holes", "[filesystem][ext2][inode]")
-{
- auto const block_size = 1024uz;
- GIVEN("an ext2 inode with only direct mapped data blocks")
- {
- auto device = kstd::make_shared<kernel::tests::devices::block_device>(0, 0, "mock", block_size, 64 * block_size);
- REQUIRE(device != nullptr);
- kernel::tests::filesystem::ext2::setup_mock_ext2_layout(*device);
-
- auto dev_inode = kstd::make_shared<kernel::filesystem::device_inode>(device);
-
- auto fs = kernel::filesystem::ext2::filesystem{};
- REQUIRE(fs.mount(dev_inode) == kernel::filesystem::filesystem::operation_result::success);
-
- auto data = kernel::filesystem::ext2::inode_data{};
- data.block[0] = 30;
- data.block[1] = 0;
- data.block[2] = 31;
- data.size = block_size * 3;
-
- kernel::tests::filesystem::ext2::write_bytes(*device, 30 * block_size, "Hello", 5);
- kernel::tests::filesystem::ext2::write_bytes(*device, 31 * block_size, "World!", 6);
-
- auto inode = kernel::filesystem::ext2::inode{&fs, data};
-
- auto buffer = kstd::vector<std::byte>(data.size, std::byte{0xAB});
-
- THEN("correct number of bytes are read and holes are returned as zeros")
- {
- auto const bytes_read = inode.read(buffer.data(), 0, buffer.size());
- REQUIRE(bytes_read == data.size);
-
- auto const text = std::string_view{reinterpret_cast<char const *>(buffer.data()), bytes_read};
- REQUIRE(text.substr(0, 5) == "Hello");
- REQUIRE(std::ranges::all_of(text.substr(5, block_size - 5), [](char c) { return c == '\0'; }));
- REQUIRE(text.substr(2 * block_size, 6) == "World!");
- REQUIRE(std::ranges::all_of(text.substr(2 * block_size + 6, 3 * block_size), [](char c) { return c == '\0'; }));
- }
- }
-
- GIVEN("an ext2 indode with file holes in singly indirect blocks")
- {
- auto device = kstd::make_shared<kernel::tests::devices::block_device>(0, 0, "mock", block_size, 64 * block_size);
- REQUIRE(device != nullptr);
- kernel::tests::filesystem::ext2::setup_mock_ext2_layout(*device);
-
- auto dev_inode = kstd::make_shared<kernel::filesystem::device_inode>(device);
-
- auto fs = kernel::filesystem::ext2::filesystem{};
- REQUIRE(fs.mount(dev_inode) == kernel::filesystem::filesystem::operation_result::success);
-
- auto data = kernel::filesystem::ext2::inode_data{};
- data.block[0] = 30;
- data.block[12] = 31;
- data.size = block_size * 15;
-
- kernel::tests::filesystem::ext2::write_u32(*device, 31 * block_size, 50);
- kernel::tests::filesystem::ext2::write_u32(*device, 31 * block_size + 4, 0);
- kernel::tests::filesystem::ext2::write_u32(*device, 31 * block_size + 8, 51);
-
- kernel::tests::filesystem::ext2::write_bytes(*device, 30 * block_size, "Hello", 5);
- kernel::tests::filesystem::ext2::write_bytes(*device, 50 * block_size, "Blub", 4);
- kernel::tests::filesystem::ext2::write_bytes(*device, 51 * block_size, "World!", 6);
-
- auto inode = kernel::filesystem::ext2::inode{&fs, data};
-
- auto buffer = kstd::vector<std::byte>(data.size, std::byte{0xAB});
-
- THEN("correct number of bytes are read and holes are returned as zeros")
- {
- auto const bytes_read = inode.read(buffer.data(), 0, buffer.size());
- REQUIRE(bytes_read == data.size);
-
- auto const text = std::string_view{reinterpret_cast<char const *>(buffer.data()), bytes_read};
- REQUIRE(text.substr(0, 5) == "Hello");
- REQUIRE(std::ranges::all_of(text.substr(5, 12 * block_size - 5), [](char c) { return c == '\0'; }));
- REQUIRE(text.substr(12 * block_size, 4) == "Blub");
- REQUIRE(
- std::ranges::all_of(text.substr(12 * block_size + 4, 2 * block_size - 4), [](char c) { return c == '\0'; }));
- REQUIRE(text.substr(14 * block_size, 6) == "World!");
- REQUIRE(
- std::ranges::all_of(text.substr(14 * block_size + 6, 1 * block_size - 6), [](char c) { return c == '\0'; }));
- }
- }
-
- GIVEN("an ext2 inode with zero singly indirect block pointer")
- {
- auto device = kstd::make_shared<kernel::tests::devices::block_device>(0, 0, "mock", block_size, 64 * block_size);
- REQUIRE(device != nullptr);
- kernel::tests::filesystem::ext2::setup_mock_ext2_layout(*device);
-
- auto dev_inode = kstd::make_shared<kernel::filesystem::device_inode>(device);
-
- auto fs = kernel::filesystem::ext2::filesystem{};
- REQUIRE(fs.mount(dev_inode) == kernel::filesystem::filesystem::operation_result::success);
-
- auto data = kernel::filesystem::ext2::inode_data{};
- data.block[12] = 0;
- data.size = block_size * 15;
-
- auto inode = kernel::filesystem::ext2::inode{&fs, data};
-
- auto buffer = kstd::vector<std::byte>(block_size * 15, std::byte{0xAB});
-
- THEN("all direct blocks are zero when singly indirect block pointer is zero")
- {
- auto const bytes_read = inode.read(buffer.data(), 0, buffer.size());
- REQUIRE(bytes_read == buffer.size());
- REQUIRE(std::ranges::all_of(buffer, [](std::byte c) { return c == std::byte{0x00}; }));
- }
- }
-}
-
-SCENARIO("Ext2 inode read across block boundaries", "[filesystem][ext2][inode]")
-{
- auto const block_size = 1024uz;
- GIVEN("an ext2 inode with two direct blocks and a block size of 1024 bytes")
- {
- auto device = kstd::make_shared<kernel::tests::devices::block_device>(0, 0, "mock", block_size, 64 * block_size);
- REQUIRE(device != nullptr);
- kernel::tests::filesystem::ext2::setup_mock_ext2_layout(*device);
-
- auto dev_inode = kstd::make_shared<kernel::filesystem::device_inode>(device);
-
- auto fs = kernel::filesystem::ext2::filesystem{};
- REQUIRE(fs.mount(dev_inode) == kernel::filesystem::filesystem::operation_result::success);
-
- auto inode_data = kernel::filesystem::ext2::inode_data{};
- inode_data.size = block_size * 2;
- inode_data.block[0] = 20;
- kernel::tests::filesystem::ext2::write_bytes(*device, 21 * block_size - 6, "Hello ", 6);
- inode_data.block[1] = 21;
- kernel::tests::filesystem::ext2::write_bytes(*device, 21 * block_size, "World!", 6);
- auto inode = kernel::filesystem::ext2::inode{&fs, inode_data};
-
- auto buffer = kstd::vector<std::byte>(12, std::byte{0x00});
-
- THEN("reading across the block boundary returns the combined content")
- {
- auto const bytes_read = inode.read(buffer.data(), block_size - 6, buffer.size());
- REQUIRE(bytes_read == 12);
-
- auto const text = std::string_view{reinterpret_cast<char const *>(buffer.data()), bytes_read};
- REQUIRE(text == "Hello World!");
- }
- }
-}
-
-SCENARIO("Ext2 inode write is not implemented", "[filesystem][ext2][inode]")
-{
- GIVEN("an ext2 inode")
- {
- auto fs = kernel::filesystem::ext2::filesystem{};
- auto inode = kernel::filesystem::ext2::inode{&fs, kernel::filesystem::ext2::inode_data{}};
-
- THEN("writing to the inode panics")
- {
- auto buffer = kstd::vector<std::byte>(32, std::byte{0x00});
- REQUIRE_THROWS_AS(inode.write(buffer.data(), 0, buffer.size()), kernel::tests::cpu::halt);
- }
- }
-}
-
-SCENARIO("Ext2 inode get_size() correctly returns size depending on revision level", "[filesystem][ext2][inode]")
-{
- auto const block_size = 1024uz;
-
- 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.inode_size = 128;
-
- GIVEN("an ext2 inode with good old revision and inode_data.size = 256, inode_data.dir_acl = 32")
- {
- superblock.rev_level = 0;
-
- auto device = kstd::make_shared<kernel::tests::devices::block_device>(0, 0, "mock", block_size, 64 * block_size);
- REQUIRE(device != nullptr);
- kernel::tests::filesystem::ext2::setup_mock_ext2_layout(*device, superblock);
-
- auto dev_inode = kstd::make_shared<kernel::filesystem::device_inode>(device);
-
- auto fs = kernel::filesystem::ext2::filesystem{};
- REQUIRE(fs.mount(dev_inode) == kernel::filesystem::filesystem::operation_result::success);
-
- auto data = kernel::filesystem::ext2::inode_data{};
- data.size = 256;
- data.dir_acl = 32;
-
- THEN("the inode size is 256 if mode = regular")
- {
- data.mode = kernel::filesystem::ext2::constants::mode_regular;
-
- auto inode = kernel::filesystem::ext2::inode{&fs, data};
-
- REQUIRE(inode.size() == 256);
- }
-
- THEN("the inode size is 256 if mode = directory")
- {
- data.mode = kernel::filesystem::ext2::constants::mode_directory;
-
- auto inode = kernel::filesystem::ext2::inode{&fs, data};
-
- REQUIRE(inode.size() == 256);
- }
- }
-
- GIVEN("an ext2 inode with good dynamic revision and inode_data.size = 256, inode_data.dir_acl = 32")
- {
- superblock.rev_level = 1;
-
- auto device = kstd::make_shared<kernel::tests::devices::block_device>(0, 0, "mock", block_size, 64 * block_size);
- REQUIRE(device != nullptr);
- kernel::tests::filesystem::ext2::setup_mock_ext2_layout(*device, superblock);
-
- auto dev_inode = kstd::make_shared<kernel::filesystem::device_inode>(device);
-
- auto fs = kernel::filesystem::ext2::filesystem{};
- REQUIRE(fs.mount(dev_inode) == kernel::filesystem::filesystem::operation_result::success);
-
- auto data = kernel::filesystem::ext2::inode_data{};
- data.size = 256;
- data.dir_acl = 32;
-
- THEN("the inode size is 256 if mode = regular")
- {
- data.mode = kernel::filesystem::ext2::constants::mode_regular;
-
- auto inode = kernel::filesystem::ext2::inode{&fs, data};
-
- REQUIRE(inode.size() == 0x0000'0020'0000'0100);
- }
-
- THEN("the inode size is 256 if mode = directory")
- {
- data.mode = kernel::filesystem::ext2::constants::mode_directory;
-
- auto inode = kernel::filesystem::ext2::inode{&fs, data};
-
- REQUIRE(inode.size() == 256);
- }
- }
-} \ No newline at end of file
diff --git a/kernel/src/filesystem/filesystem.cpp b/kernel/src/filesystem/filesystem.cpp
deleted file mode 100644
index 24d0e229..00000000
--- a/kernel/src/filesystem/filesystem.cpp
+++ /dev/null
@@ -1,60 +0,0 @@
-#include <kernel/filesystem/filesystem.hpp>
-
-#include <kernel/filesystem/ext2/filesystem.hpp>
-#include <kernel/filesystem/inode.hpp>
-
-#include <kapi/system.hpp>
-
-#include <kstd/memory>
-
-#include <array>
-
-namespace kernel::filesystem
-{
- namespace
- {
- constexpr auto static filesystem_factories = std::array{
- []() { return kstd::make_shared<ext2::filesystem>(); },
- };
- } // namespace
-
- auto filesystem::probe_and_mount(kstd::shared_ptr<inode> const & backing_inode) -> kstd::shared_ptr<filesystem>
- {
- if (!backing_inode)
- {
- kapi::system::panic("[FILESYSTEM] cannot mount filesystem: backing inode is null.");
- }
-
- for (auto & factory : filesystem_factories)
- {
- auto fs = factory();
- if (fs->mount(backing_inode) == operation_result::success)
- {
- return fs;
- }
- }
-
- return nullptr;
- }
-
- auto filesystem::mount(kstd::shared_ptr<inode> const & backing_inode) -> operation_result
- {
- if (!backing_inode)
- {
- kapi::system::panic("[FILESYSTEM] cannot mount filesystem: backing inode is null.");
- }
-
- m_backing_inode = backing_inode;
- return operation_result::success;
- }
-
- auto filesystem::root_inode() const -> kstd::shared_ptr<inode> const &
- {
- return m_root_inode;
- }
-
- auto filesystem::backing_inode() const -> kstd::shared_ptr<inode> const &
- {
- return m_backing_inode;
- }
-} // namespace kernel::filesystem \ No newline at end of file
diff --git a/kernel/src/filesystem/inode.cpp b/kernel/src/filesystem/inode.cpp
deleted file mode 100644
index c1889179..00000000
--- a/kernel/src/filesystem/inode.cpp
+++ /dev/null
@@ -1,24 +0,0 @@
-#include <kernel/filesystem/inode.hpp>
-
-namespace kernel::filesystem
-{
- auto inode::is_directory() const -> bool
- {
- return false;
- }
-
- auto inode::is_regular() const -> bool
- {
- return false;
- }
-
- auto inode::is_device() const -> bool
- {
- return false;
- }
-
- auto inode::is_symbolic_link() const -> bool
- {
- return false;
- }
-} // namespace kernel::filesystem \ No newline at end of file
diff --git a/kernel/src/filesystem/mount.cpp b/kernel/src/filesystem/mount.cpp
deleted file mode 100644
index ead7479d..00000000
--- a/kernel/src/filesystem/mount.cpp
+++ /dev/null
@@ -1,90 +0,0 @@
-#include <kernel/filesystem/mount.hpp>
-
-#include <kernel/filesystem/dentry.hpp>
-#include <kernel/filesystem/filesystem.hpp>
-
-#include <kapi/system.hpp>
-
-#include <kstd/memory>
-#include <kstd/string>
-
-#include <cstddef>
-#include <string_view>
-
-namespace kernel::filesystem
-{
- mount::mount(kstd::shared_ptr<dentry> const & mount_dentry, kstd::shared_ptr<dentry> const & root_dentry,
- kstd::shared_ptr<filesystem> const & fs, kstd::shared_ptr<mount> const & parent_mount,
- kstd::shared_ptr<mount> const & source_mount)
- : m_mount_dentry(mount_dentry)
- , m_root_dentry(root_dentry)
- , m_filesystem(fs)
- , m_parent_mount(parent_mount)
- , m_source_mount(source_mount)
- , m_ref_count(0)
- {
- if (!m_filesystem)
- {
- kapi::system::panic("[FILESYSTEM] mount initialized with null filesystem.");
- }
- }
-
- auto mount::mount_dentry() const -> kstd::shared_ptr<dentry> const &
- {
- return m_mount_dentry;
- }
-
- auto mount::get_filesystem() const -> kstd::shared_ptr<filesystem> const &
- {
- return m_filesystem;
- }
-
- auto mount::root_dentry() const -> kstd::shared_ptr<dentry> const &
- {
- return m_root_dentry;
- }
-
- auto mount::mount_path() const -> kstd::string
- {
- if (m_mount_dentry)
- {
- return m_mount_dentry->absolute_path();
- }
- return "/";
- }
-
- auto mount::parent_mount() const -> kstd::shared_ptr<mount> const &
- {
- return m_parent_mount;
- }
-
- auto mount::source_mount() const -> kstd::shared_ptr<mount>
- {
- return m_source_mount.lock();
- }
-
- auto mount::increment_ref_count() -> void
- {
- m_ref_count += 1;
- }
-
- auto mount::decrement_ref_count() -> void
- {
- if (m_ref_count == 0)
- {
- kapi::system::panic("[FILESYSTEM] decrement_ref_count() was called but ref_count is 0");
- }
-
- m_ref_count -= 1;
- }
-
- auto mount::is_ready_to_unmount() const -> bool
- {
- return m_ref_count == 0;
- }
-
- auto mount::ref_count() const -> size_t
- {
- return m_ref_count;
- }
-} // namespace kernel::filesystem \ No newline at end of file
diff --git a/kernel/src/filesystem/mount.tests.cpp b/kernel/src/filesystem/mount.tests.cpp
deleted file mode 100644
index c9ff82e9..00000000
--- a/kernel/src/filesystem/mount.tests.cpp
+++ /dev/null
@@ -1,94 +0,0 @@
-#include <kernel/filesystem/mount.hpp>
-
-#include <kernel/filesystem/dentry.hpp>
-#include <kernel/test_support/cpu.hpp>
-#include <kernel/test_support/filesystem/filesystem.hpp>
-#include <kernel/test_support/filesystem/inode.hpp>
-
-#include <kstd/memory>
-#include <kstd/print>
-#include <kstd/vector>
-
-#include <catch2/catch_test_macros.hpp>
-
-#include <stdexcept>
-
-SCENARIO("Mount construction", "[filesystem][mount]")
-{
- GIVEN("a filesystem and a root dentry")
- {
- auto fs = kstd::make_shared<kernel::tests::filesystem::filesystem>();
- auto root_inode = kstd::make_shared<kernel::tests::filesystem::inode>();
- auto root_dentry = kstd::make_shared<kernel::filesystem::dentry>(nullptr, root_inode, "/");
-
- WHEN("constructing a mount with the filesystem and root dentry")
- {
- auto mount = kernel::filesystem::mount{root_dentry, root_dentry, fs, nullptr, nullptr};
-
- THEN("the mount has the correct filesystem, root dentry, mount dentry, and mount path")
- {
- REQUIRE(mount.get_filesystem() == fs);
- REQUIRE(mount.root_dentry() == root_dentry);
- REQUIRE(mount.mount_dentry() == root_dentry);
- REQUIRE(mount.mount_path() == "/");
- REQUIRE(mount.is_ready_to_unmount());
- }
-
- THEN("the mount has no parent mount and no source mount")
- {
- REQUIRE(mount.parent_mount() == nullptr);
- REQUIRE(mount.source_mount() == nullptr);
- }
- }
-
- WHEN("constructing a mount with a null filesystem")
- {
- THEN("the constructor panics")
- {
- REQUIRE_THROWS_AS((kernel::filesystem::mount{root_dentry, root_dentry, nullptr, nullptr, nullptr}),
- kernel::tests::cpu::halt);
- }
- }
- }
-}
-
-SCENARIO("Mount reference counting", "[filesystem][mount]")
-{
- GIVEN("a filesystem and a root dentry")
- {
- auto fs = kstd::make_shared<kernel::tests::filesystem::filesystem>();
- auto root_inode = kstd::make_shared<kernel::tests::filesystem::inode>();
- auto root_dentry = kstd::make_shared<kernel::filesystem::dentry>(nullptr, root_inode, "/");
-
- THEN("reference count can be incremented and decremented, the mount is ready to unmount when the reference "
- "count == 0")
- {
- auto mount = kernel::filesystem::mount{root_dentry, root_dentry, fs, nullptr, nullptr};
-
- mount.increment_ref_count();
- REQUIRE(mount.ref_count() == 1);
- REQUIRE_FALSE(mount.is_ready_to_unmount());
-
- mount.increment_ref_count();
- REQUIRE(mount.ref_count() == 2);
- REQUIRE_FALSE(mount.is_ready_to_unmount());
-
- mount.decrement_ref_count();
- REQUIRE(mount.ref_count() == 1);
- REQUIRE_FALSE(mount.is_ready_to_unmount());
-
- mount.decrement_ref_count();
- REQUIRE(mount.ref_count() == 0);
- REQUIRE(mount.is_ready_to_unmount());
- }
-
- THEN("decrementing reference count when it is already zero does not decrement it below zero")
- {
- auto mount = kernel::filesystem::mount{root_dentry, root_dentry, fs, nullptr, nullptr};
-
- REQUIRE_THROWS_AS(mount.decrement_ref_count(), std::runtime_error);
- REQUIRE(mount.ref_count() == 0);
- REQUIRE(mount.is_ready_to_unmount());
- }
- }
-} \ No newline at end of file
diff --git a/kernel/src/filesystem/mount_table.cpp b/kernel/src/filesystem/mount_table.cpp
deleted file mode 100644
index e4baac7a..00000000
--- a/kernel/src/filesystem/mount_table.cpp
+++ /dev/null
@@ -1,79 +0,0 @@
-#include <kernel/filesystem/mount_table.hpp>
-
-#include <kernel/filesystem/dentry.hpp>
-#include <kernel/filesystem/mount.hpp>
-
-#include <kstd/memory>
-#include <kstd/vector>
-
-#include <algorithm>
-#include <ranges>
-#include <string_view>
-
-namespace kernel::filesystem
-{
- auto mount_table::has_child_mounts(kstd::shared_ptr<mount> const & parent_mount) const -> bool
- {
- return std::ranges::any_of(m_mounts,
- [&parent_mount](auto const & mount) { return mount->parent_mount() == parent_mount; });
- }
-
- auto mount_table::add_mount(kstd::shared_ptr<mount> const & mount) -> void
- {
- m_mounts.push_back(mount);
-
- if (auto source_mount = mount->source_mount())
- {
- source_mount->increment_ref_count();
- }
-
- if (auto mount_dentry = mount->mount_dentry())
- {
- mount_dentry->set_flag(dentry::dentry_flags::is_mount_point);
- }
- }
-
- auto mount_table::remove_mount(std::string_view path) -> operation_result
- {
- auto mount_it = find_mount_iterator(path);
- if (mount_it == m_mounts.end())
- {
- return operation_result::mount_not_found;
- }
-
- auto const & mount = *mount_it;
- if (!mount->is_ready_to_unmount())
- {
- return operation_result::cannot_be_unmounted;
- }
- if (has_child_mounts(mount))
- {
- return operation_result::has_child_mounts;
- }
-
- if (auto source_mount = mount->source_mount())
- {
- source_mount->decrement_ref_count();
- }
-
- if (auto mount_dentry = mount->mount_dentry())
- {
- mount_dentry->unset_flag(dentry::dentry_flags::is_mount_point);
- }
-
- m_mounts.erase(mount_it);
- return operation_result::removed;
- }
-
- auto mount_table::find_mount(std::string_view path) const -> kstd::shared_ptr<mount>
- {
- auto mount_it = find_mount_iterator(path);
- return (mount_it != m_mounts.end()) ? *mount_it : nullptr;
- }
-
- auto mount_table::find_mount_iterator(std::string_view path) const
- -> kstd::vector<kstd::shared_ptr<mount>>::const_iterator
- {
- return std::ranges::find_last_if(m_mounts, [&](auto const & mount) { return mount->mount_path() == path; }).begin();
- }
-} // namespace kernel::filesystem \ No newline at end of file
diff --git a/kernel/src/filesystem/mount_table.tests.cpp b/kernel/src/filesystem/mount_table.tests.cpp
deleted file mode 100644
index 19b47b23..00000000
--- a/kernel/src/filesystem/mount_table.tests.cpp
+++ /dev/null
@@ -1,184 +0,0 @@
-#include <kernel/filesystem/mount_table.hpp>
-
-#include <kernel/filesystem/dentry.hpp>
-#include <kernel/filesystem/mount.hpp>
-#include <kernel/test_support/filesystem/filesystem.hpp>
-#include <kernel/test_support/filesystem/inode.hpp>
-
-#include <kstd/memory>
-#include <kstd/print>
-#include <kstd/vector>
-
-#include <catch2/catch_test_macros.hpp>
-
-#include <string_view>
-
-SCENARIO("Mount table construction", "[filesystem][mount_table]")
-{
- GIVEN("an empty mount table")
- {
- kernel::filesystem::mount_table table;
-
- THEN("removing any mount returns mount_not_found")
- {
- REQUIRE(table.remove_mount("/") == kernel::filesystem::mount_table::operation_result::mount_not_found);
- REQUIRE(table.remove_mount("/any/path") == kernel::filesystem::mount_table::operation_result::mount_not_found);
- }
- }
-}
-
-SCENARIO("Adding, finding and removing mounts in the mount table", "[filesystem][mount_table]")
-{
- GIVEN("a mount table and some mounts")
- {
- kernel::filesystem::mount_table table;
-
- auto fs1 = kstd::make_shared<kernel::tests::filesystem::filesystem>();
- auto root_dentry1 = kstd::make_shared<kernel::filesystem::dentry>(
- nullptr, kstd::make_shared<kernel::tests::filesystem::inode>(), "/");
- auto mount_dentry1 = kstd::make_shared<kernel::filesystem::dentry>(
- nullptr, kstd::make_shared<kernel::tests::filesystem::inode>(), "/");
- auto mount1 = kstd::make_shared<kernel::filesystem::mount>(mount_dentry1, root_dentry1, fs1, nullptr, nullptr);
-
- auto fs2 = kstd::make_shared<kernel::tests::filesystem::filesystem>();
- auto root_dentry2 = kstd::make_shared<kernel::filesystem::dentry>(
- nullptr, kstd::make_shared<kernel::tests::filesystem::inode>(), "/");
- auto mount_dentry2 = kstd::make_shared<kernel::filesystem::dentry>(
- nullptr, kstd::make_shared<kernel::tests::filesystem::inode>(), "/mnt");
- auto mount2 = kstd::make_shared<kernel::filesystem::mount>(mount_dentry2, root_dentry2, fs2, nullptr, nullptr);
-
- table.add_mount(mount1);
- table.add_mount(mount2);
-
- THEN("dentry flags are set correctly for mounted dentries")
- {
- REQUIRE(mount_dentry1->has_flag(kernel::filesystem::dentry::dentry_flags::is_mount_point));
- REQUIRE(mount_dentry2->has_flag(kernel::filesystem::dentry::dentry_flags::is_mount_point));
- }
-
- THEN("finding mounts by exact valid path returns the correct mount")
- {
- REQUIRE(table.find_mount("/") == mount1);
- REQUIRE(table.find_mount("/mnt") == mount2);
- }
-
- THEN("finding mounts by exact invalid path returns null")
- {
- REQUIRE(table.find_mount("/nonexistent") == nullptr);
- REQUIRE(table.find_mount("/mnt/file") == nullptr);
- }
-
- THEN("removing a mount that has no child mounts succeeds")
- {
- REQUIRE(table.remove_mount("/mnt") == kernel::filesystem::mount_table::operation_result::removed);
- REQUIRE_FALSE(root_dentry2->has_flag(kernel::filesystem::dentry::dentry_flags::is_mount_point));
- }
-
- THEN("removing a mount that does not exist returns mount_not_found")
- {
- REQUIRE(table.remove_mount("/nonexistent") == kernel::filesystem::mount_table::operation_result::mount_not_found);
- }
- }
-
- GIVEN("multiple mounts with the same path")
- {
- kernel::filesystem::mount_table table;
-
- auto fs1 = kstd::make_shared<kernel::tests::filesystem::filesystem>();
- auto root_dentry1 = kstd::make_shared<kernel::filesystem::dentry>(
- nullptr, kstd::make_shared<kernel::tests::filesystem::inode>(), "/");
- auto mount_dentry1 = kstd::make_shared<kernel::filesystem::dentry>(
- nullptr, kstd::make_shared<kernel::tests::filesystem::inode>(), "/");
- auto mount1 = kstd::make_shared<kernel::filesystem::mount>(mount_dentry1, root_dentry1, fs1, nullptr, nullptr);
-
- auto fs2 = kstd::make_shared<kernel::tests::filesystem::filesystem>();
- auto root_dentry2 = kstd::make_shared<kernel::filesystem::dentry>(
- nullptr, kstd::make_shared<kernel::tests::filesystem::inode>(), "/");
- auto mount_dentry2 = kstd::make_shared<kernel::filesystem::dentry>(
- nullptr, kstd::make_shared<kernel::tests::filesystem::inode>(), "/");
- auto mount2 = kstd::make_shared<kernel::filesystem::mount>(mount_dentry2, root_dentry2, fs2, nullptr, nullptr);
-
- table.add_mount(mount1);
- table.add_mount(mount2);
-
- THEN("finding mounts by exact valid path returns the correct mount")
- {
- REQUIRE(table.find_mount("/") == mount2);
- }
-
- THEN("removing the topmost mount with the same path succeeds")
- {
- REQUIRE(table.remove_mount("/") == kernel::filesystem::mount_table::operation_result::removed);
- REQUIRE_FALSE(root_dentry2->has_flag(kernel::filesystem::dentry::dentry_flags::is_mount_point));
- }
- }
-
- GIVEN("a mount with child mounts")
- {
- kernel::filesystem::mount_table table;
-
- auto fs1 = kstd::make_shared<kernel::tests::filesystem::filesystem>();
- auto root_dentry1 = kstd::make_shared<kernel::filesystem::dentry>(
- nullptr, kstd::make_shared<kernel::tests::filesystem::inode>(), "/");
- auto mount_dentry1 = kstd::make_shared<kernel::filesystem::dentry>(
- nullptr, kstd::make_shared<kernel::tests::filesystem::inode>(), "/");
- auto mount1 = kstd::make_shared<kernel::filesystem::mount>(mount_dentry1, root_dentry1, fs1, nullptr, nullptr);
-
- auto fs2 = kstd::make_shared<kernel::tests::filesystem::filesystem>();
- auto root_dentry2 = kstd::make_shared<kernel::filesystem::dentry>(
- nullptr, kstd::make_shared<kernel::tests::filesystem::inode>(), "/");
- auto mount_dentry2 = kstd::make_shared<kernel::filesystem::dentry>(
- mount_dentry1, kstd::make_shared<kernel::tests::filesystem::inode>(), "mnt");
- auto mount2 = kstd::make_shared<kernel::filesystem::mount>(mount_dentry2, root_dentry2, fs2, mount1, nullptr);
-
- auto fs3 = kstd::make_shared<kernel::tests::filesystem::filesystem>();
- auto root_dentry3 = kstd::make_shared<kernel::filesystem::dentry>(
- nullptr, kstd::make_shared<kernel::tests::filesystem::inode>(), "/");
- auto mount_dentry3 = kstd::make_shared<kernel::filesystem::dentry>(
- mount_dentry2, kstd::make_shared<kernel::tests::filesystem::inode>(), "submnt");
- auto mount3 = kstd::make_shared<kernel::filesystem::mount>(mount_dentry3, root_dentry3, fs3, mount2, nullptr);
-
- table.add_mount(mount1);
- table.add_mount(mount2);
- table.add_mount(mount3);
-
- THEN("removing a mount with child mounts returns has_child_mounts")
- {
- REQUIRE(table.remove_mount("/") == kernel::filesystem::mount_table::operation_result::has_child_mounts);
- REQUIRE(table.remove_mount("/mnt") == kernel::filesystem::mount_table::operation_result::has_child_mounts);
- }
-
- THEN("removing a leaf mount succeeds")
- {
- REQUIRE(table.remove_mount("/mnt/submnt") == kernel::filesystem::mount_table::operation_result::removed);
- REQUIRE_FALSE(root_dentry3->has_flag(kernel::filesystem::dentry::dentry_flags::is_mount_point));
- }
- }
-}
-
-SCENARIO("Mount reference counting", "[filesystem][mount_table]")
-{
- kernel::filesystem::mount_table table;
-
- GIVEN("a filesystem and a root dentry")
- {
- auto fs = kstd::make_shared<kernel::tests::filesystem::filesystem>();
- auto root_inode = kstd::make_shared<kernel::tests::filesystem::inode>();
- auto root_dentry = kstd::make_shared<kernel::filesystem::dentry>(nullptr, root_inode, "/");
-
- auto source_mount = kstd::make_shared<kernel::filesystem::mount>(root_dentry, root_dentry, fs, nullptr, nullptr);
- auto mount = kstd::make_shared<kernel::filesystem::mount>(root_dentry, root_dentry, fs, nullptr, source_mount);
-
- THEN("reference count of source mount is incremented when a mount is added to the mount table and decremented when "
- "the mount is removed")
- {
- REQUIRE(source_mount->ref_count() == 0);
-
- table.add_mount(mount);
- REQUIRE(source_mount->ref_count() == 1);
-
- REQUIRE(table.remove_mount("/") == kernel::filesystem::mount_table::operation_result::removed);
- REQUIRE(source_mount->ref_count() == 0);
- }
- }
-}
diff --git a/kernel/src/filesystem/open_file_descriptor.cpp b/kernel/src/filesystem/open_file_descriptor.cpp
deleted file mode 100644
index a5567bf4..00000000
--- a/kernel/src/filesystem/open_file_descriptor.cpp
+++ /dev/null
@@ -1,46 +0,0 @@
-#include <kernel/filesystem/open_file_descriptor.hpp>
-
-#include <kernel/filesystem/dentry.hpp>
-
-#include <kstd/memory>
-#include <kstd/os/error.hpp>
-
-#include <cstddef>
-
-namespace kernel::filesystem
-{
- open_file_descriptor::open_file_descriptor(kstd::shared_ptr<dentry> const & dentry)
- : m_dentry(dentry)
- , m_offset(0)
- {
- if (!dentry)
- {
- kstd::os::panic("[FILESYSTEM] open_file_descriptor constructed with null dentry.");
- }
- }
-
- auto open_file_descriptor::read(void * buffer, size_t size) -> size_t
- {
- auto read_bytes = m_dentry->get_inode()->read(buffer, m_offset, size);
- m_offset += read_bytes;
- return read_bytes;
- }
-
- auto open_file_descriptor::write(void const * buffer, size_t size) -> size_t
- {
- auto written_bytes = m_dentry->get_inode()->write(buffer, m_offset, size);
- m_offset += written_bytes;
- return written_bytes;
- }
-
- auto open_file_descriptor::offset() const -> size_t
- {
- return m_offset;
- }
-
- auto open_file_descriptor::get_dentry() const -> kstd::shared_ptr<dentry> const &
- {
- return m_dentry;
- }
-
-} // namespace kernel::filesystem \ No newline at end of file
diff --git a/kernel/src/filesystem/open_file_descriptor.tests.cpp b/kernel/src/filesystem/open_file_descriptor.tests.cpp
deleted file mode 100644
index 8c24cf0e..00000000
--- a/kernel/src/filesystem/open_file_descriptor.tests.cpp
+++ /dev/null
@@ -1,113 +0,0 @@
-#include <kernel/filesystem/open_file_descriptor.hpp>
-
-#include <kernel/filesystem/dentry.hpp>
-#include <kernel/filesystem/inode.hpp>
-#include <kernel/filesystem/vfs.hpp>
-#include <kernel/test_support/filesystem/inode.hpp>
-#include <kernel/test_support/filesystem/storage_boot_module_vfs_fixture.hpp>
-
-#include <kstd/memory>
-#include <kstd/print>
-#include <kstd/vector>
-
-#include <catch2/catch_test_macros.hpp>
-
-#include <cstddef>
-#include <filesystem>
-#include <string_view>
-
-SCENARIO("Open file descriptor construction", "[filesystem][open_file_descriptor]")
-{
- GIVEN("a dentry and an open file descriptor for that dentry")
- {
- auto inode = kstd::make_shared<kernel::tests::filesystem::inode>();
- auto dentry = kstd::make_shared<kernel::filesystem::dentry>(nullptr, inode, "test_dentry");
- auto file_descriptor = kernel::filesystem::open_file_descriptor{dentry};
-
- THEN("the initial offset is zero")
- {
- REQUIRE(file_descriptor.offset() == 0);
- }
- }
-}
-
-SCENARIO("Open file descriptor read/write offset management", "[filesystem][open_file_descriptor]")
-{
- GIVEN("a dentry that tracks read/write calls and an open file descriptor for that dentry")
- {
- auto inode = kstd::make_shared<kernel::tests::filesystem::inode>();
- auto dentry = kstd::make_shared<kernel::filesystem::dentry>(nullptr, inode, "test_dentry");
- auto file_descriptor = kernel::filesystem::open_file_descriptor{dentry};
-
- THEN("the offset is updated correctly after reads")
- {
- REQUIRE(file_descriptor.read(nullptr, 100) == 100);
- REQUIRE(file_descriptor.offset() == 100);
- REQUIRE(file_descriptor.read(nullptr, 50) == 50);
- REQUIRE(file_descriptor.offset() == 150);
- }
-
- THEN("the offset is updated correctly after writes")
- {
- REQUIRE(file_descriptor.write(nullptr, 200) == 200);
- REQUIRE(file_descriptor.offset() == 200);
- REQUIRE(file_descriptor.write(nullptr, 25) == 25);
- REQUIRE(file_descriptor.offset() == 225);
- }
-
- THEN("reads and writes both update the same offset")
- {
- REQUIRE(file_descriptor.read(nullptr, 10) == 10);
- REQUIRE(file_descriptor.offset() == 10);
- REQUIRE(file_descriptor.write(nullptr, 20) == 20);
- REQUIRE(file_descriptor.offset() == 30);
- REQUIRE(file_descriptor.read(nullptr, 5) == 5);
- REQUIRE(file_descriptor.offset() == 35);
- REQUIRE(file_descriptor.write(nullptr, 15) == 15);
- REQUIRE(file_descriptor.offset() == 50);
- }
- }
-}
-
-SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_vfs_fixture, "Open file descriptor read with real image",
- "[filesystem][open_file_descriptor][img]")
-{
- auto const image_path = std::filesystem::path{KERNEL_TEST_ASSETS_DIR} / "ext2_1KB_fs.img";
-
- GIVEN("an open file descriptor for a file in a real image")
- {
- REQUIRE(std::filesystem::exists(image_path));
- REQUIRE_NOTHROW(setup_modules_from_img_and_init_vfs({"test_img_module"}, {image_path}));
-
- auto & vfs = kernel::filesystem::vfs::get();
- auto dentry = vfs.open("/information/info_1.txt");
- REQUIRE(dentry != nullptr);
- auto ofd = kstd::make_shared<kernel::filesystem::open_file_descriptor>(dentry);
-
- THEN("the file can be read and the offset is updated")
- {
- kstd::vector<std::byte> buffer(32);
- auto bytes_read = ofd->read(buffer.data(), buffer.size());
- REQUIRE(bytes_read == 7);
- REQUIRE(ofd->offset() == 7);
-
- std::string_view buffer_as_str{reinterpret_cast<char *>(buffer.data()), static_cast<size_t>(bytes_read)};
- REQUIRE(buffer_as_str == "info_1\n");
- }
-
- THEN("the file can be read multiple times")
- {
- kstd::vector<std::byte> buffer(4);
- auto bytes_read_1 = ofd->read(buffer.data(), buffer.size() / 2);
- REQUIRE(bytes_read_1 == buffer.size() / 2);
- REQUIRE(ofd->offset() == buffer.size() / 2);
-
- auto bytes_read_2 = ofd->read(buffer.data() + buffer.size() / 2, buffer.size() / 2);
- REQUIRE(bytes_read_2 == buffer.size() / 2);
- REQUIRE(ofd->offset() == buffer.size());
-
- std::string_view buffer_as_str{reinterpret_cast<char *>(buffer.data()), bytes_read_1 + bytes_read_2};
- REQUIRE(buffer_as_str == "info");
- }
- }
-}
diff --git a/kernel/src/filesystem/open_file_table.cpp b/kernel/src/filesystem/open_file_table.cpp
deleted file mode 100644
index 2afe3aa4..00000000
--- a/kernel/src/filesystem/open_file_table.cpp
+++ /dev/null
@@ -1,87 +0,0 @@
-#include <kernel/filesystem/open_file_table.hpp>
-
-#include <kernel/filesystem/open_file_descriptor.hpp>
-
-#include <kapi/system.hpp>
-
-#include <kstd/memory>
-#include <kstd/unikstd.h>
-
-#include <algorithm>
-#include <cstddef>
-#include <optional>
-
-namespace
-{
- constinit auto static global_open_file_table = std::optional<kernel::filesystem::open_file_table>{};
-} // namespace
-
-namespace kernel::filesystem
-{
- auto open_file_table::init() -> void
- {
- if (global_open_file_table)
- {
- kapi::system::panic("[FILESYSTEM] Open file table has already been initialized.");
- }
-
- global_open_file_table.emplace(open_file_table{});
- }
-
- auto open_file_table::get() -> open_file_table &
- {
- if (!global_open_file_table)
- {
- kapi::system::panic("[FILESYSTEM] Open file table has not been initialized.");
- }
-
- return *global_open_file_table;
- }
-
- auto open_file_table::add_file(kstd::shared_ptr<open_file_descriptor> const & file_descriptor) -> kstd::ssize_t
- {
- if (!file_descriptor)
- {
- return -1;
- }
-
- auto it = std::ranges::find_if(m_open_files, [](auto const & open_file) { return open_file == nullptr; });
- if (it != m_open_files.end())
- {
- *it = file_descriptor;
- return it - m_open_files.begin();
- }
-
- m_open_files.push_back(file_descriptor);
- return m_open_files.size() - 1;
- }
-
- auto open_file_table::file(size_t fd) const -> kstd::shared_ptr<open_file_descriptor>
- {
- if (fd >= m_open_files.size())
- {
- return nullptr;
- }
-
- return m_open_files.at(fd);
- }
-
- auto open_file_table::remove_file(size_t fd) -> kstd::ssize_t
- {
- if (fd >= m_open_files.size())
- {
- return -1;
- }
-
- m_open_files.at(fd) = nullptr;
- return 0;
- }
-} // namespace kernel::filesystem
-
-namespace kernel::tests::filesystem::open_file_table
-{
- auto deinit() -> void
- {
- global_open_file_table.reset();
- }
-} // namespace kernel::tests::filesystem::open_file_table
diff --git a/kernel/src/filesystem/open_file_table.tests.cpp b/kernel/src/filesystem/open_file_table.tests.cpp
deleted file mode 100644
index 3e91111d..00000000
--- a/kernel/src/filesystem/open_file_table.tests.cpp
+++ /dev/null
@@ -1,106 +0,0 @@
-#include <kernel/filesystem/open_file_table.hpp>
-
-#include <kernel/filesystem/dentry.hpp>
-#include <kernel/filesystem/open_file_descriptor.hpp>
-#include <kernel/test_support/filesystem/inode.hpp>
-
-#include <kstd/memory>
-#include <kstd/print>
-#include <kstd/vector>
-
-#include <catch2/catch_test_macros.hpp>
-
-SCENARIO("Open file table add/get file", "[filesystem][open_file_table]")
-{
- GIVEN("a open file table and an open file descriptor")
- {
- auto & table = kernel::filesystem::open_file_table::get();
- auto inode = kstd::make_shared<kernel::tests::filesystem::inode>();
- auto dentry = kstd::make_shared<kernel::filesystem::dentry>(nullptr, inode, "test_dentry");
-
- auto file_descriptor_1 = kstd::make_shared<kernel::filesystem::open_file_descriptor>(dentry);
- auto file_descriptor_2 = kstd::make_shared<kernel::filesystem::open_file_descriptor>(dentry);
-
- WHEN("adding the open file descriptor to the open file table")
- {
- auto fd_1 = table.add_file(file_descriptor_1);
- auto fd_2 = table.add_file(file_descriptor_2);
- auto fd_3 = table.add_file(file_descriptor_2);
-
- THEN("a valid file descriptor is returned")
- {
- REQUIRE(fd_1 == 0);
- REQUIRE(fd_2 == 1);
- REQUIRE(fd_3 == 2);
- }
-
- THEN("the file descriptor can be retrieved using the returned file descriptor")
- {
- auto retrieved_descriptor = table.file(fd_1);
- REQUIRE(retrieved_descriptor == file_descriptor_1);
- }
- }
- }
-
- GIVEN("a invalid open file descriptor")
- {
- auto & table = kernel::filesystem::open_file_table::get();
-
- THEN("adding a null file descriptor returns an error code")
- {
- auto fd = table.add_file(nullptr);
- REQUIRE(fd == -1);
- }
-
- THEN("retrieving a file descriptor with an out-of-bounds file descriptor returns a null pointer")
- {
- auto retrieved_descriptor = table.file(1000);
- REQUIRE(retrieved_descriptor == nullptr);
- }
- }
-}
-
-SCENARIO("Open file table remove file", "[filesystem][open_file_table]")
-{
- GIVEN("a open file table with an open file descriptor")
- {
- auto & table = kernel::filesystem::open_file_table::get();
- auto inode = kstd::make_shared<kernel::tests::filesystem::inode>();
- auto dentry = kstd::make_shared<kernel::filesystem::dentry>(nullptr, inode, "test_dentry");
- auto file_descriptor = kstd::make_shared<kernel::filesystem::open_file_descriptor>(dentry);
- auto fd = table.add_file(file_descriptor);
-
- WHEN("removing the file descriptor using the file descriptor")
- {
- table.remove_file(fd);
-
- THEN("the file descriptor can no longer be retrieved using the file descriptor")
- {
- auto retrieved_descriptor = table.file(fd);
- REQUIRE(retrieved_descriptor == nullptr);
- }
- }
-
- WHEN("removing a file descriptor the other file descriptor keep the same index")
- {
- auto fd2 = table.add_file(file_descriptor);
- table.remove_file(fd);
-
- THEN("the second file descriptor can still be retrieved using its file descriptor")
- {
- auto retrieved_descriptor = table.file(fd2);
- REQUIRE(retrieved_descriptor == file_descriptor);
- }
- }
- }
-
- GIVEN("an invalid file descriptor")
- {
- auto & table = kernel::filesystem::open_file_table::get();
-
- THEN("removing a file with an out-of-bounds file descriptor does nothing")
- {
- REQUIRE_NOTHROW(table.remove_file(1000));
- }
- }
-} \ No newline at end of file
diff --git a/kernel/src/filesystem/path.tests.cpp b/kernel/src/filesystem/path.tests.cpp
deleted file mode 100644
index 3c18b5c2..00000000
--- a/kernel/src/filesystem/path.tests.cpp
+++ /dev/null
@@ -1,69 +0,0 @@
-#include <kernel/filesystem/path.hpp>
-
-#include <catch2/catch_test_macros.hpp>
-
-#include <algorithm>
-#include <string>
-#include <string_view>
-#include <vector>
-
-SCENARIO("path utilities", "[filesystem][path]")
-{
- GIVEN("valid and invalid paths")
- {
- THEN("valid absolute paths are recognized as valid")
- {
- REQUIRE(kernel::filesystem::path::is_valid_path("/valid/absolute/path"));
- REQUIRE(kernel::filesystem::path::is_valid_path("/"));
- }
-
- THEN("valid relative paths are recognized as valid")
- {
- REQUIRE(kernel::filesystem::path::is_valid_path("valid/../relative/.././path"));
- REQUIRE(kernel::filesystem::path::is_valid_path("valid/relative/path"));
- REQUIRE(kernel::filesystem::path::is_valid_path("file.txt"));
- }
-
- THEN("invalid paths are recognized as invalid")
- {
- REQUIRE_FALSE(kernel::filesystem::path::is_valid_path(""));
- REQUIRE_FALSE(kernel::filesystem::path::is_valid_path(std::string(4096, 'a')));
- }
-
- THEN("valid absolute paths are recognized as absolute")
- {
- REQUIRE(kernel::filesystem::path::is_valid_absolute_path("/valid/absolute/path"));
- REQUIRE_FALSE(kernel::filesystem::path::is_valid_absolute_path("valid/relative/path"));
- }
-
- THEN("invalid paths are not recognized as absolute")
- {
- REQUIRE_FALSE(kernel::filesystem::path::is_valid_absolute_path(""));
- REQUIRE_FALSE(kernel::filesystem::path::is_valid_absolute_path(std::string(4096, 'a')));
- REQUIRE_FALSE(kernel::filesystem::path::is_valid_absolute_path("invalid/absolute/path"));
- }
-
- THEN("valid relative paths are recognized as relative")
- {
- REQUIRE(kernel::filesystem::path::is_valid_relative_path("valid/relative/path"));
- REQUIRE_FALSE(kernel::filesystem::path::is_valid_relative_path("/valid/absolute/path"));
- }
-
- THEN("invalid paths are not recognized as relative")
- {
- REQUIRE_FALSE(kernel::filesystem::path::is_valid_relative_path(""));
- REQUIRE_FALSE(kernel::filesystem::path::is_valid_relative_path(std::string(4096, 'a')));
- REQUIRE_FALSE(kernel::filesystem::path::is_valid_relative_path("/invalid/absolute/path"));
- }
- }
-
- GIVEN("a valid path")
- {
- THEN("it can be split into components")
- {
- auto components = kernel::filesystem::path::split("/a/b///c/d.txt");
- std::vector<std::string_view> expected = {"a", "b", "c", "d.txt"};
- REQUIRE(std::ranges::equal(components, expected));
- }
- }
-} \ No newline at end of file
diff --git a/kernel/src/filesystem/rootfs/filesystem.cpp b/kernel/src/filesystem/rootfs/filesystem.cpp
deleted file mode 100644
index 7fe5c1ea..00000000
--- a/kernel/src/filesystem/rootfs/filesystem.cpp
+++ /dev/null
@@ -1,47 +0,0 @@
-#include <kernel/filesystem/rootfs/filesystem.hpp>
-
-#include <kernel/filesystem/filesystem.hpp>
-#include <kernel/filesystem/inode.hpp>
-#include <kernel/filesystem/rootfs/inode.hpp>
-#include <kernel/filesystem/type.hpp>
-
-#include <kstd/memory>
-
-#include <string_view>
-
-namespace kernel::filesystem::rootfs
-{
-
- struct type final : kernel::filesystem::type
- {
- [[nodiscard]] auto name() const noexcept -> std::string_view override
- {
- return "rootfs";
- }
-
- [[nodiscard]] auto requires_device() const noexcept -> bool override
- {
- return true;
- }
-
- [[nodiscard]] auto make_instance() const -> kstd::shared_ptr<kernel::filesystem::filesystem> override
- {
- return kstd::make_shared<filesystem>();
- }
- };
-
- [[gnu::used]]
- constexpr auto registration = type_registration<type>{};
-
- auto filesystem::mount(kstd::shared_ptr<kernel::filesystem::inode> const &) -> operation_result
- {
- m_root_inode = kstd::make_shared<inode>();
- return operation_result::success;
- }
-
- auto filesystem::lookup(kstd::shared_ptr<kernel::filesystem::inode> const &, std::string_view) const
- -> kstd::shared_ptr<kernel::filesystem::inode>
- {
- return nullptr;
- }
-} // namespace kernel::filesystem::rootfs
diff --git a/kernel/src/filesystem/rootfs/filesystem.tests.cpp b/kernel/src/filesystem/rootfs/filesystem.tests.cpp
deleted file mode 100644
index ae320e95..00000000
--- a/kernel/src/filesystem/rootfs/filesystem.tests.cpp
+++ /dev/null
@@ -1,38 +0,0 @@
-#include <kernel/filesystem/rootfs/filesystem.hpp>
-
-#include <kernel/filesystem/filesystem.hpp>
-
-#include <kstd/memory>
-#include <kstd/print>
-#include <kstd/vector>
-
-#include <catch2/catch_test_macros.hpp>
-
-SCENARIO("Rootfs filesystem mount and lookup", "[filesystem][rootfs][filesystem]")
-{
- GIVEN("a mounted rootfs filesystem")
- {
- auto fs = kernel::filesystem::rootfs::filesystem{};
- auto result = fs.mount(nullptr);
-
- THEN("the filesystem can be mounted successfully")
- {
- REQUIRE(result == kernel::filesystem::filesystem::operation_result::success);
- REQUIRE(fs.root_inode() != nullptr);
- }
-
- THEN("looking up a non-existent directory returns null")
- {
- auto non_existent_inode_1 = fs.lookup(fs.root_inode(), "");
- REQUIRE(non_existent_inode_1 == nullptr);
- auto non_existent_inode_2 = fs.lookup(fs.root_inode(), "nonexistent");
- REQUIRE(non_existent_inode_2 == nullptr);
- }
-
- THEN("looking up with a null parent inode returns null")
- {
- auto result = fs.lookup(nullptr, "dev");
- REQUIRE(result == nullptr);
- }
- }
-}
diff --git a/kernel/src/filesystem/rootfs/inode.cpp b/kernel/src/filesystem/rootfs/inode.cpp
deleted file mode 100644
index f64fb87c..00000000
--- a/kernel/src/filesystem/rootfs/inode.cpp
+++ /dev/null
@@ -1,23 +0,0 @@
-#include <kernel/filesystem/inode.hpp>
-
-#include <kernel/filesystem/rootfs/inode.hpp>
-
-#include <cstddef>
-
-namespace kernel::filesystem::rootfs
-{
- auto inode::read(void *, size_t, size_t) const -> size_t
- {
- return 0;
- }
-
- auto inode::write(void const *, size_t, size_t) -> size_t
- {
- return 0;
- }
-
- auto inode::is_directory() const -> bool
- {
- return true;
- }
-} // namespace kernel::filesystem::rootfs
diff --git a/kernel/src/filesystem/rootfs/inode.tests.cpp b/kernel/src/filesystem/rootfs/inode.tests.cpp
deleted file mode 100644
index f4b634fa..00000000
--- a/kernel/src/filesystem/rootfs/inode.tests.cpp
+++ /dev/null
@@ -1,37 +0,0 @@
-#include <kernel/filesystem/rootfs/inode.hpp>
-
-#include <kstd/memory>
-#include <kstd/print>
-#include <kstd/vector>
-
-#include <catch2/catch_test_macros.hpp>
-
-SCENARIO("Rootfs inode read/write", "[filesystem][rootfs][inode]")
-{
- GIVEN("a rootfs inode")
- {
- auto inode = kernel::filesystem::rootfs::inode{};
-
- WHEN("reading from the inode")
- {
- kstd::vector<char> buffer(10);
- auto bytes_read = inode.read(buffer.data(), 0, buffer.size());
-
- THEN("no bytes are read")
- {
- REQUIRE(bytes_read == 0);
- }
- }
-
- WHEN("writing to the inode")
- {
- kstd::vector<char> buffer(10, 'x');
- auto bytes_written = inode.write(buffer.data(), 0, buffer.size());
-
- THEN("no bytes are written")
- {
- REQUIRE(bytes_written == 0);
- }
- }
- }
-}
diff --git a/kernel/src/filesystem/type_registry.cpp b/kernel/src/filesystem/type_registry.cpp
deleted file mode 100644
index 74b12090..00000000
--- a/kernel/src/filesystem/type_registry.cpp
+++ /dev/null
@@ -1,76 +0,0 @@
-#include <kernel/filesystem/type_registry.hpp>
-
-#include <kapi/system.hpp>
-
-#include <kstd/memory>
-#include <kstd/print>
-
-#include <algorithm>
-#include <cstddef>
-#include <optional>
-#include <ranges>
-#include <span>
-
-namespace kernel::filesystem
-{
-
- extern "C"
- {
- // We need to suppress clang-tidy linting warnings here, since these symbols are generated by the linker and we
- // cannot choose their names, unless we wanted to extend the linker script needlessly.
- // NOLINTBEGIN(readability-identifier-naming)
- extern type_registry::pointer const __start_fs_types;
- extern type_registry::pointer const __stop_fs_types;
- // NOLINTEND(readability-identifier-naming)
- }
-
- namespace
- {
- auto constinit instance = std::optional<type_registry>{};
- }
-
- auto type_registry::init() -> void
- {
- if (instance)
- {
- kapi::system::panic("[FILESYSTEM] tried to initialize type registry more than once!");
- }
-
- instance.emplace();
-
- auto type_descriptors = std::span{&__start_fs_types, &__stop_fs_types} | //
- std::views::filter([](auto p) { return p != nullptr; });
-
- std::ranges::for_each(type_descriptors, [](auto descriptor) {
- kstd::println("[FILESYSTEM] registering '{}'", descriptor->name());
- instance->add(descriptor);
- });
- }
-
- auto type_registry::get() -> type_registry &
- {
- if (!instance)
- {
- kapi::system::panic("[FILESYSTEM] type registry has not been initialized!");
- }
-
- return *instance;
- }
-
- auto type_registry::add(pointer descriptor) -> bool
- {
- auto result = m_descriptors.emplace(descriptor->name(), descriptor);
- return result.second;
- }
-
- auto type_registry::all() const noexcept -> std::span<pointer const>
- {
- return {m_descriptors.values().begin(), m_descriptors.values().end()};
- }
-
- auto type_registry::size() const noexcept -> std::size_t
- {
- return m_descriptors.size();
- }
-
-} // namespace kernel::filesystem
diff --git a/kernel/src/filesystem/type_registry.tests.cpp b/kernel/src/filesystem/type_registry.tests.cpp
deleted file mode 100644
index 8382579f..00000000
--- a/kernel/src/filesystem/type_registry.tests.cpp
+++ /dev/null
@@ -1,77 +0,0 @@
-#include <kernel/filesystem/type_registry.hpp>
-
-#include <kernel/filesystem/filesystem.hpp>
-#include <kernel/filesystem/type.hpp>
-
-#include <kstd/memory>
-
-#include <catch2/catch_test_macros.hpp>
-
-#include <iterator>
-#include <string_view>
-
-struct test_type final : kernel::filesystem::type
-{
- [[nodiscard]] auto name() const noexcept -> std::string_view override
- {
- return "bht_testfs";
- }
-
- [[nodiscard]] auto requires_device() const noexcept -> bool override
- {
- return false;
- }
-
- [[nodiscard]] auto make_instance() const -> kstd::shared_ptr<kernel::filesystem::filesystem> override
- {
- return nullptr;
- }
-};
-
-SCENARIO("Filesystem type registry initialization and construction", "[filesystem]")
-{
- GIVEN("A default constructed type_registry")
- {
- auto instance = kernel::filesystem::type_registry{};
-
- WHEN("getting the span of filesystem descriptors")
- {
- auto descriptors = instance.all();
-
- THEN("the span is empty")
- {
- REQUIRE(descriptors.empty());
- }
- }
- }
-}
-
-SCENARIO("Filesystem type registry modifiers", "[filesystem]")
-{
- GIVEN("A default constructed type_registry")
- {
- auto instance = kernel::filesystem::type_registry{};
-
- WHEN("adding a type descriptor")
- {
- auto descriptor = test_type{};
-
- instance.add(kstd::make_observer(&descriptor));
-
- THEN("the size of the registry is one")
- {
- REQUIRE(instance.size() == 1);
- }
-
- THEN("the span is not empty")
- {
- REQUIRE_FALSE(instance.all().empty());
- }
-
- THEN("the span's size is equal to the registry size")
- {
- REQUIRE(std::size(instance.all()) == std::size(instance));
- }
- }
- }
-}
diff --git a/kernel/src/filesystem/vfs.cpp b/kernel/src/filesystem/vfs.cpp
deleted file mode 100644
index e5dff8c4..00000000
--- a/kernel/src/filesystem/vfs.cpp
+++ /dev/null
@@ -1,299 +0,0 @@
-#include <kernel/filesystem/vfs.hpp>
-
-#include <kernel/filesystem/constants.hpp>
-#include <kernel/filesystem/dentry.hpp>
-#include <kernel/filesystem/devfs/filesystem.hpp>
-#include <kernel/filesystem/filesystem.hpp>
-#include <kernel/filesystem/mount.hpp>
-#include <kernel/filesystem/mount_table.hpp>
-#include <kernel/filesystem/path.hpp>
-#include <kernel/filesystem/rootfs/filesystem.hpp>
-
-#include <kapi/system.hpp>
-
-#include <kstd/memory>
-#include <kstd/vector>
-
-#include <algorithm>
-#include <cstdint>
-#include <optional>
-#include <ranges>
-#include <string_view>
-#include <utility>
-
-namespace
-{
- constinit auto static active_vfs = std::optional<kernel::filesystem::vfs>{};
-} // namespace
-
-namespace kernel::filesystem
-{
- auto vfs::init() -> void
- {
- if (active_vfs)
- {
- kapi::system::panic("[FILESYSTEM] vfs has already been initialized.");
- }
-
- active_vfs.emplace();
- }
-
- vfs::vfs()
- {
- // mount rootfs at /
- auto root_fs = kstd::make_shared<rootfs::filesystem>();
- root_fs->mount(nullptr);
-
- auto root_fs_root_dentry = kstd::make_shared<dentry>(nullptr, root_fs->root_inode(), "/");
- auto root_mount = kstd::make_shared<mount>(nullptr, root_fs_root_dentry, root_fs, nullptr, nullptr);
- m_mount_table.add_mount(root_mount);
-
- // mount devfs at /dev (inside rootfs, temporary, will be shadowed)
- auto device_fs = kstd::make_shared<devfs::filesystem>();
- device_fs->mount(nullptr);
- graft_persistent_device_fs(device_fs);
-
- // mount boot fs at / (shadows rootfs), re-graft devfs
- auto [boot_device_dentry, boot_device_mount_context] = resolve_path_internal("/dev/ram0");
- if (boot_device_dentry && boot_device_mount_context)
- {
- if (auto boot_root_fs = kernel::filesystem::filesystem::probe_and_mount(boot_device_dentry->get_inode()))
- {
- if (auto root_dentry = resolve_path("/"))
- {
- do_mount_internal(root_dentry, root_mount, boot_root_fs, boot_device_mount_context);
- graft_persistent_device_fs(device_fs);
- }
- }
- }
- }
-
- auto vfs::get() -> vfs &
- {
- if (!active_vfs)
- {
- kapi::system::panic("[FILESYSTEM] vfs has not been initialized.");
- }
-
- return *active_vfs;
- }
-
- auto vfs::open(std::string_view path) -> kstd::shared_ptr<dentry>
- {
- auto [dentry, mount] = resolve_path_internal(path);
- if (!dentry || !mount)
- {
- return nullptr;
- }
- mount->increment_ref_count();
- return dentry;
- }
-
- auto vfs::close(std::string_view path) -> operation_result
- {
- if (auto mount = find_mount(path))
- {
- mount->decrement_ref_count();
- return operation_result::success;
- }
- return operation_result::invalid_path;
- }
-
- auto vfs::do_mount(std::string_view source, std::string_view target) -> operation_result
- {
- if (!path::is_valid_path(source) || !path::is_valid_path(target))
- {
- return operation_result::invalid_path;
- }
-
- auto [mount_point_dentry, mount_context] = resolve_path_internal(target);
- if (mount_point_dentry && mount_context)
- {
- auto [source_dentry, source_mount_context] = resolve_path_internal(source);
- if (source_dentry && source_mount_context)
- {
- if (auto fs = kernel::filesystem::filesystem::probe_and_mount(source_dentry->get_inode()))
- {
- do_mount_internal(mount_point_dentry, mount_context, fs, source_mount_context);
- return operation_result::success;
- }
- return operation_result::invalid_filesystem;
- }
- return operation_result::non_existent_path;
- }
- return operation_result::mount_point_not_found;
- }
-
- auto vfs::unmount(std::string_view path) -> operation_result
- {
- if (!path::is_valid_path(path))
- {
- return operation_result::invalid_path;
- }
-
- auto remove_result = m_mount_table.remove_mount(path);
- if (remove_result == mount_table::operation_result::removed)
- {
- return operation_result::success;
- }
- else if (remove_result == mount_table::operation_result::mount_not_found)
- {
- return operation_result::mount_point_not_found;
- }
-
- return operation_result::unmount_failed;
- }
-
- auto vfs::do_mount_internal(kstd::shared_ptr<dentry> const & mount_point_dentry,
- kstd::shared_ptr<mount> const & parent_mount, kstd::shared_ptr<filesystem> const & fs,
- kstd::shared_ptr<mount> const & source_mount) -> void
- {
- auto new_fs_root =
- kstd::make_shared<dentry>(mount_point_dentry->parent(), fs->root_inode(), mount_point_dentry->name());
- auto new_mount = kstd::make_shared<mount>(mount_point_dentry, new_fs_root, fs, parent_mount, source_mount);
- m_mount_table.add_mount(new_mount);
- }
-
- auto vfs::graft_persistent_device_fs(kstd::shared_ptr<devfs::filesystem> const & device_fs) -> void
- {
- auto [root_mount_point_dentry, root_mount] = resolve_path_internal("/");
- if (root_mount_point_dentry && root_mount)
- {
- auto dev_dentry = root_mount_point_dentry->find_child("dev");
- if (!dev_dentry)
- {
- dev_dentry = kstd::make_shared<dentry>(root_mount_point_dentry, device_fs->root_inode(), "dev");
- root_mount_point_dentry->add_child(dev_dentry);
- }
-
- do_mount_internal(dev_dentry, root_mount, device_fs);
- }
- }
-
- auto vfs::resolve_path_internal(std::string_view path) const
- -> std::pair<kstd::shared_ptr<dentry>, kstd::shared_ptr<mount>>
- {
- if (!path::is_valid_absolute_path(path))
- {
- return {nullptr, nullptr};
- }
-
- auto current_mount = m_mount_table.find_mount("/");
- if (!current_mount)
- {
- kapi::system::panic("[FILESYSTEM] no root mount found.");
- }
-
- auto current_dentry = current_mount->root_dentry();
-
- auto path_parts = path::split(path);
- kstd::vector path_parts_vector(path_parts.begin(), path_parts.end());
- std::ranges::reverse(path_parts_vector);
-
- auto symlink_counter = 0uz;
-
- while (!path_parts_vector.empty())
- {
- auto part = path_parts_vector.back();
- path_parts_vector.pop_back();
-
- if (part == ".")
- {
- continue;
- }
-
- if (part == "..")
- {
- auto parent_dentry = current_dentry->parent();
-
- if (current_dentry == current_mount->root_dentry())
- {
- if (current_mount->mount_path() == "/")
- {
- continue;
- }
-
- if (auto parent_mount = current_mount->parent_mount())
- {
- current_mount = parent_mount;
- current_dentry = parent_dentry;
- }
- }
-
- current_dentry = parent_dentry;
- continue;
- }
-
- auto next_dentry = current_dentry->find_child(part);
- if (!next_dentry)
- {
- auto current_fs = current_mount->get_filesystem();
- auto found_inode = current_fs->lookup(current_dentry->get_inode(), part);
- if (!found_inode)
- {
- return {nullptr, nullptr};
- }
-
- next_dentry = kstd::make_shared<dentry>(current_dentry, found_inode, part);
- current_dentry->add_child(next_dentry);
- }
- else if (next_dentry->has_flag(dentry::dentry_flags::is_mount_point))
- {
- current_mount = m_mount_table.find_mount(next_dentry->absolute_path());
- if (!current_mount)
- {
- kapi::system::panic("[FILESYSTEM] mount for dentry with mounted flag not found.");
- }
-
- next_dentry = current_mount->root_dentry();
- }
-
- if (next_dentry->get_inode()->is_symbolic_link())
- {
- if (symlink_counter++ > constants::symloop_max)
- {
- return {nullptr, nullptr};
- }
-
- kstd::vector<uint8_t> buffer(constants::symlink_max_path_length);
- auto const bytes_read = next_dentry->get_inode()->read(buffer.data(), 0, buffer.size());
- auto const symbolic_link_path = std::string_view{reinterpret_cast<char const *>(buffer.data()), bytes_read};
-
- auto symbolic_link_parts = path::split(symbolic_link_path);
- kstd::vector symbolic_link_parts_vector(symbolic_link_parts.begin(), symbolic_link_parts.end());
- std::ranges::reverse(symbolic_link_parts_vector);
-
- path_parts_vector.insert_range(path_parts_vector.end(), symbolic_link_parts_vector);
-
- if (path::is_valid_absolute_path(symbolic_link_path))
- {
- current_mount = m_mount_table.find_mount("/");
- current_dentry = current_mount->root_dentry();
- }
- continue;
- }
-
- current_dentry = next_dentry;
- }
- return {current_dentry, current_mount};
- }
-
- auto vfs::resolve_path(std::string_view path) const -> kstd::shared_ptr<dentry>
- {
- return resolve_path_internal(path).first;
- }
-
- auto vfs::find_mount(std::string_view path) const -> kstd::shared_ptr<mount>
- {
- return resolve_path_internal(path).second;
- }
-
-} // namespace kernel::filesystem
-
-namespace kernel::tests::filesystem::vfs
-{
- auto deinit() -> void
- {
- active_vfs.reset();
- }
-} // namespace kernel::tests::filesystem::vfs
diff --git a/kernel/src/filesystem/vfs.tests.cpp b/kernel/src/filesystem/vfs.tests.cpp
deleted file mode 100644
index f1d0df0d..00000000
--- a/kernel/src/filesystem/vfs.tests.cpp
+++ /dev/null
@@ -1,568 +0,0 @@
-#include <kernel/filesystem/vfs.hpp>
-
-#include <kernel/filesystem/open_file_descriptor.hpp>
-#include <kernel/test_support/filesystem/storage_boot_module_vfs_fixture.hpp>
-
-#include <kstd/memory>
-#include <kstd/vector>
-
-#include <catch2/catch_test_macros.hpp>
-
-#include <cstddef>
-#include <filesystem>
-#include <stdexcept>
-#include <string_view>
-
-SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_vfs_fixture, "VFS with dummy modules",
- "[filesystem][vfs]")
-{
- GIVEN("an initialized boot module registry with multiple modules")
- {
- REQUIRE_NOTHROW(setup_modules_and_init_vfs(5));
-
- THEN("vfs initializes and provides /dev mount")
- {
- auto & vfs = kernel::filesystem::vfs::get();
- auto dev = vfs.open("/dev");
-
- REQUIRE(dev != nullptr);
- }
-
- THEN("vfs initializes root filesystem with boot device if boot module is present")
- {
- auto & vfs = kernel::filesystem::vfs::get();
- auto root_file = vfs.open("/");
-
- REQUIRE(root_file != nullptr);
- }
- }
-}
-
-SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_vfs_fixture, "VFS with file backed image",
- "[filesystem][vfs][img]")
-{
- auto const image_path_1 = std::filesystem::path{KERNEL_TEST_ASSETS_DIR} / "ext2_1KB_fs.img";
- auto const image_path_2 = std::filesystem::path{KERNEL_TEST_ASSETS_DIR} / "ext2_2KB_fs.img";
- auto const image_path_3 = std::filesystem::path{KERNEL_TEST_ASSETS_DIR} / "ext2_4KB_fs.img";
-
- GIVEN("a real image file")
- {
- REQUIRE(std::filesystem::exists(image_path_1));
- REQUIRE_NOTHROW(setup_modules_from_img_and_init_vfs({"test_img_module"}, {image_path_1}));
-
- THEN("vfs initializes and provides expected mount points")
- {
- auto & vfs = kernel::filesystem::vfs::get();
- auto root = vfs.open("/");
- auto dev = vfs.open("/dev");
- auto information = vfs.open("/information/info_1.txt");
-
- REQUIRE(root != nullptr);
- REQUIRE(dev != nullptr);
- REQUIRE(information != nullptr);
- }
- }
-
- GIVEN("a real image file containing a /dev directory")
- {
- REQUIRE(std::filesystem::exists(image_path_2));
- REQUIRE_NOTHROW(setup_modules_from_img_and_init_vfs({"test_img_module_2"}, {image_path_2}));
-
- THEN("vfs hides the image's /dev behind the devfs mount")
- {
- auto & vfs = kernel::filesystem::vfs::get();
-
- auto image_1 = vfs.open("/dev/image_1.txt");
- REQUIRE(image_1 == nullptr);
-
- auto dev = vfs.open("/dev/ram0");
- REQUIRE(dev != nullptr);
- }
- }
-
- GIVEN("three real image files")
- {
- REQUIRE(std::filesystem::exists(image_path_1));
- REQUIRE(std::filesystem::exists(image_path_2));
- REQUIRE(std::filesystem::exists(image_path_3));
- REQUIRE_NOTHROW(setup_modules_from_img_and_init_vfs({"test_img_module_1", "test_img_module_2", "test_img_module_3"},
- {image_path_1, image_path_2, image_path_3}));
-
- auto & vfs = kernel::filesystem::vfs::get();
-
- THEN("vfs initializes first module as root")
- {
- auto & vfs = kernel::filesystem::vfs::get();
- auto info1 = vfs.open("/information/info_1.txt");
- auto info2 = vfs.open("/information/info_2.txt");
-
- REQUIRE(info1 != nullptr);
- REQUIRE(info2 != nullptr);
- }
-
- THEN("second image can be mounted, data retrieved and unmounted again")
- {
- REQUIRE(vfs.do_mount("/dev/ram16", "/information") == kernel::filesystem::vfs::operation_result::success);
-
- auto mounted_monkey_1 = vfs.open("/information/monkey_house/monkey_1.txt");
- REQUIRE(mounted_monkey_1 != nullptr);
- REQUIRE(vfs.close(mounted_monkey_1->absolute_path()) == kernel::filesystem::vfs::operation_result::success);
-
- REQUIRE(vfs.unmount("/information") == kernel::filesystem::vfs::operation_result::success);
- auto unmounted_monkey_1 = vfs.open("/information/monkey_house/monkey_1.txt");
- REQUIRE(unmounted_monkey_1 == nullptr);
-
- auto info_1 = vfs.open("/information/info_1.txt");
- REQUIRE(info_1 != nullptr);
- }
-
- THEN("third image can be mounted in a mounted file system, unmount only if no child mount exists")
- {
- REQUIRE(vfs.do_mount("/dev/ram16", "/information") == kernel::filesystem::vfs::operation_result::success);
- REQUIRE(vfs.do_mount("/dev/ram32", "/information/monkey_house/infrastructure") ==
- kernel::filesystem::vfs::operation_result::success);
-
- auto mounted_monkey_1 = vfs.open("/information/monkey_house/monkey_1.txt");
- auto mounted_fish1 = vfs.open("/information/monkey_house/infrastructure/enclosures/aquarium/tank_1/fish_1.txt");
-
- REQUIRE(mounted_monkey_1 != nullptr);
- REQUIRE(mounted_fish1 != nullptr);
-
- REQUIRE(vfs.close(mounted_monkey_1->absolute_path()) == kernel::filesystem::vfs::operation_result::success);
- REQUIRE(vfs.close(mounted_fish1->absolute_path()) == kernel::filesystem::vfs::operation_result::success);
-
- REQUIRE(vfs.unmount("/information") == kernel::filesystem::vfs::operation_result::unmount_failed);
- REQUIRE(vfs.unmount("/information/monkey_house/infrastructure") ==
- kernel::filesystem::vfs::operation_result::success);
- REQUIRE(vfs.unmount("/information") == kernel::filesystem::vfs::operation_result::success);
- }
-
- THEN("image can be mounted, unmount only if no files are open")
- {
- REQUIRE(vfs.do_mount("/dev/ram16", "/information") == kernel::filesystem::vfs::operation_result::success);
-
- auto mounted_monkey_1 = vfs.open("/information/monkey_house/monkey_1.txt");
- REQUIRE(mounted_monkey_1 != nullptr);
-
- REQUIRE(vfs.unmount("/information") == kernel::filesystem::vfs::operation_result::unmount_failed);
-
- REQUIRE(vfs.close(mounted_monkey_1->absolute_path()) == kernel::filesystem::vfs::operation_result::success);
-
- REQUIRE(vfs.unmount("/information") == kernel::filesystem::vfs::operation_result::success);
- }
-
- THEN("file with invalid path or not opened file cannot be closed")
- {
- REQUIRE(vfs.close("invalid_path") == kernel::filesystem::vfs::operation_result::invalid_path);
- REQUIRE_THROWS_AS(vfs.close("/information/info_1.txt"), std::runtime_error);
- }
-
- THEN("file cannot be closed twice")
- {
- auto info_1 = vfs.open("/information/info_1.txt");
- REQUIRE(info_1 != nullptr);
-
- REQUIRE(vfs.close(info_1->absolute_path()) == kernel::filesystem::vfs::operation_result::success);
- REQUIRE_THROWS_AS(vfs.close(info_1->absolute_path()), std::runtime_error);
- }
-
- THEN("images can be stacked mounted and correct file system is unmounted again")
- {
- REQUIRE(vfs.do_mount("/dev/ram16", "/information") == kernel::filesystem::vfs::operation_result::success);
- REQUIRE(vfs.do_mount("/dev/ram32", "/information") == kernel::filesystem::vfs::operation_result::success);
-
- auto mounted_tickets = vfs.open("/information/entrance/tickets.txt");
- REQUIRE(mounted_tickets != nullptr);
-
- REQUIRE(vfs.close(mounted_tickets->absolute_path()) == kernel::filesystem::vfs::operation_result::success);
-
- REQUIRE(vfs.unmount("/information") == kernel::filesystem::vfs::operation_result::success);
- mounted_tickets = vfs.open("/information/entrance/tickets.txt");
- REQUIRE(mounted_tickets == nullptr);
-
- auto mounted_monkey = vfs.open("/information/monkey_house/monkey_1.txt");
- REQUIRE(mounted_monkey != nullptr);
- }
-
- THEN("image can be mounted on / file opened and unmounted again")
- {
- auto info_1 = vfs.open("/information/info_1.txt");
- REQUIRE(info_1 != nullptr);
-
- REQUIRE(vfs.do_mount("/dev/ram16", "/") == kernel::filesystem::vfs::operation_result::success);
-
- info_1 = vfs.open("/information/info_1.txt");
- REQUIRE(info_1 == nullptr);
-
- auto water = vfs.open("/monkey_house/infrastructure/water.txt");
- REQUIRE(water != nullptr);
-
- REQUIRE(vfs.close(water->absolute_path()) == kernel::filesystem::vfs::operation_result::success);
-
- REQUIRE(vfs.unmount("/") == kernel::filesystem::vfs::operation_result::success);
-
- info_1 = vfs.open("/information/info_1.txt");
- REQUIRE(info_1 != nullptr);
- }
-
- THEN("image can be mounted on / just the boot root has /dev")
- {
- auto info_1 = vfs.open("/information/info_1.txt");
- REQUIRE(info_1 != nullptr);
-
- REQUIRE(vfs.do_mount("/dev/ram16", "/") == kernel::filesystem::vfs::operation_result::success);
-
- info_1 = vfs.open("/information/info_1.txt");
- REQUIRE(info_1 == nullptr);
-
- auto water = vfs.open("/monkey_house/infrastructure/water.txt");
- REQUIRE(water != nullptr);
-
- REQUIRE(vfs.close(water->absolute_path()) == kernel::filesystem::vfs::operation_result::success);
-
- auto dev_ram_16 = vfs.open("/dev/ram16");
- REQUIRE(dev_ram_16 == nullptr);
-
- REQUIRE(vfs.do_mount("/dev/ram32", "/") == kernel::filesystem::vfs::operation_result::non_existent_path);
-
- REQUIRE(vfs.unmount("/") == kernel::filesystem::vfs::operation_result::success);
-
- auto dev_ram_32 = vfs.open("/dev/ram32");
- REQUIRE(dev_ram_32 != nullptr);
- }
-
- THEN("boot root can be unmounted and remounted again but /dev is not re-grafted")
- {
- auto info_1 = vfs.open("/information/info_1.txt");
- REQUIRE(info_1 != nullptr);
-
- REQUIRE(vfs.close(info_1->absolute_path()) == kernel::filesystem::vfs::operation_result::success);
-
- REQUIRE(vfs.unmount("/dev") == kernel::filesystem::vfs::operation_result::success);
- REQUIRE(vfs.unmount("/") == kernel::filesystem::vfs::operation_result::success);
-
- info_1 = vfs.open("/information/info_1.txt");
- REQUIRE(info_1 == nullptr);
-
- REQUIRE(vfs.do_mount("/dev/ram0", "/") == kernel::filesystem::vfs::operation_result::success);
-
- info_1 = vfs.open("/information/info_1.txt");
- REQUIRE(info_1 != nullptr);
-
- auto dev_ram_0 = vfs.open("/dev/ram0");
- REQUIRE(dev_ram_0 == nullptr);
- }
-
- THEN("mount with null file system fails")
- {
- REQUIRE(vfs.do_mount("/closed.txt", "/information") ==
- kernel::filesystem::vfs::operation_result::invalid_filesystem);
- }
-
- THEN("mount with invalid path fails")
- {
- REQUIRE(vfs.do_mount("/dev/ram16", "") == kernel::filesystem::vfs::operation_result::invalid_path);
- REQUIRE(vfs.do_mount("/dev/ram16", "information") ==
- kernel::filesystem::vfs::operation_result::mount_point_not_found);
- }
-
- THEN("mount with non-existent source path fails")
- {
- REQUIRE(vfs.do_mount("/dev/nonexistent", "/information") ==
- kernel::filesystem::vfs::operation_result::non_existent_path);
- }
-
- THEN("mount with non-existent mount point fails")
- {
- REQUIRE(vfs.do_mount("/dev/ram16", "/information/nonexistent") ==
- kernel::filesystem::vfs::operation_result::mount_point_not_found);
- }
-
- THEN("unmount with invalid path fails")
- {
- REQUIRE(vfs.unmount("") == kernel::filesystem::vfs::operation_result::invalid_path);
- REQUIRE(vfs.unmount("information") == kernel::filesystem::vfs::operation_result::mount_point_not_found);
- }
-
- THEN("unmounting non-existent mount point returns expected error code")
- {
- REQUIRE(vfs.unmount("/information/nonexistent") ==
- kernel::filesystem::vfs::operation_result::mount_point_not_found);
- }
-
- THEN("a file can be access if . in the path")
- {
- auto info_1 = vfs.open("/information/./info_1.txt");
- REQUIRE(info_1 != nullptr);
- }
-
- THEN("a file can be accessed within the same mount if path contains .. ")
- {
- auto info_1 = vfs.open("/archiv/../information/info_1.txt");
- REQUIRE(info_1 != nullptr);
-
- auto img = vfs.open("/archiv/../information/../archiv/2024.img");
- REQUIRE(img != nullptr);
- }
-
- THEN("a file can be accessed over multiple mounts if path contains .. or . ")
- {
- REQUIRE(vfs.do_mount("/dev/ram16", "/information") == kernel::filesystem::vfs::operation_result::success);
-
- auto img = vfs.open("/information/monkey_house/caretaker/../../../../../../archiv/2024.img");
- REQUIRE(img != nullptr);
-
- auto dev_32 = vfs.open("/information/monkey_house/caretaker/../../../dev/ram32");
- REQUIRE(dev_32 != nullptr);
-
- auto water = vfs.open("/information/./monkey_house/infrastructure/water.txt");
- REQUIRE(water != nullptr);
- }
-
- THEN("a file can be accessed over multiple mounts (device and file) if path contains .. ")
- {
- REQUIRE(vfs.do_mount("/dev/ram16", "/information") == kernel::filesystem::vfs::operation_result::success);
- REQUIRE(vfs.do_mount("/archiv/2024.img", "/information/monkey_house/infrastructure") ==
- kernel::filesystem::vfs::operation_result::success);
-
- auto pig_1 = vfs.open("/information/monkey_house/infrastructure/stable/pig_1.txt");
- REQUIRE(pig_1 != nullptr);
-
- auto isabelle =
- vfs.open("/information/monkey_house/infrastructure/stable/../../../monkey_house/caretaker/isabelle.txt");
- REQUIRE(isabelle != nullptr);
-
- auto closed = vfs.open("/information/monkey_house/infrastructure/stable/../../../../closed.txt");
- REQUIRE(closed != nullptr);
- }
- }
-
- GIVEN("A real image file containing as filesystem formatted files")
- {
- REQUIRE(std::filesystem::exists(image_path_1));
- REQUIRE_NOTHROW(setup_modules_from_img_and_init_vfs({"test_img_module_1"}, {image_path_1}));
-
- THEN("the file-filesystem in the image can be mounted, files can be read and unmounted again")
- {
- auto & vfs = kernel::filesystem::vfs::get();
- REQUIRE(vfs.do_mount("/archiv/2024.img", "/information") == kernel::filesystem::vfs::operation_result::success);
-
- auto info_1 = vfs.open("/information/info_1.txt");
- REQUIRE(info_1 == nullptr);
-
- auto dentry = vfs.open("/information/sheep_1.txt");
- REQUIRE(dentry != nullptr);
- auto sheep_1_ofd = kstd::make_shared<kernel::filesystem::open_file_descriptor>(dentry);
-
- kstd::vector<std::byte> buffer(7);
- auto bytes_read = sheep_1_ofd->read(buffer.data(), buffer.size());
- std::string_view buffer_as_str{reinterpret_cast<char *>(buffer.data()), bytes_read};
- REQUIRE(buffer_as_str == "sheep_1");
-
- REQUIRE(vfs.close(dentry->absolute_path()) == kernel::filesystem::vfs::operation_result::success);
-
- REQUIRE(vfs.unmount("/information") == kernel::filesystem::vfs::operation_result::success);
- auto unmounted_sheep_1 = vfs.open("/information/sheep_1.txt");
- REQUIRE(unmounted_sheep_1 == nullptr);
- }
-
- THEN("the file-filesystem in the image can be mounted and in this filesystem can another file-filesystem be "
- "mounted, files can be read and unmounted again")
- {
- auto & vfs = kernel::filesystem::vfs::get();
- REQUIRE(vfs.do_mount("/archiv/2024.img", "/information") == kernel::filesystem::vfs::operation_result::success);
- REQUIRE(vfs.do_mount("/archiv/2025.img", "/information/stable") ==
- kernel::filesystem::vfs::operation_result::success);
-
- auto sheep_1 = vfs.open("/information/sheep_1.txt");
- auto goat_1 = vfs.open("/information/stable/petting_zoo/goat_1.txt");
- REQUIRE(sheep_1 != nullptr);
- REQUIRE(goat_1 != nullptr);
-
- auto sheep_1_ofd = kstd::make_shared<kernel::filesystem::open_file_descriptor>(sheep_1);
- auto goat_1_ofd = kstd::make_shared<kernel::filesystem::open_file_descriptor>(goat_1);
-
- kstd::vector<std::byte> sheep_buffer(7);
- auto bytes_read = sheep_1_ofd->read(sheep_buffer.data(), sheep_buffer.size());
- std::string_view buffer_as_str{reinterpret_cast<char *>(sheep_buffer.data()), bytes_read};
- REQUIRE(buffer_as_str == "sheep_1");
-
- kstd::vector<std::byte> goat_buffer(6);
- bytes_read = goat_1_ofd->read(goat_buffer.data(), goat_buffer.size());
- buffer_as_str = std::string_view{reinterpret_cast<char *>(goat_buffer.data()), bytes_read};
- REQUIRE(buffer_as_str == "goat_1");
-
- REQUIRE(vfs.close(sheep_1->absolute_path()) == kernel::filesystem::vfs::operation_result::success);
- REQUIRE(vfs.close(goat_1->absolute_path()) == kernel::filesystem::vfs::operation_result::success);
-
- REQUIRE(vfs.unmount("/information") == kernel::filesystem::vfs::operation_result::unmount_failed);
-
- REQUIRE(vfs.unmount("/information/stable") == kernel::filesystem::vfs::operation_result::success);
- auto unmounted_goat_1 = vfs.open("/information/stable/petting_zoo/goat_1.txt");
- REQUIRE(unmounted_goat_1 == nullptr);
-
- auto still_mounted_sheep_1 = vfs.open("/information/sheep_1.txt");
- REQUIRE(still_mounted_sheep_1 != nullptr);
-
- REQUIRE(vfs.close(still_mounted_sheep_1->absolute_path()) == kernel::filesystem::vfs::operation_result::success);
-
- REQUIRE(vfs.unmount("/information") == kernel::filesystem::vfs::operation_result::success);
- auto unmounted_sheep_1 = vfs.open("/information/sheep_1.txt");
- REQUIRE(unmounted_sheep_1 == nullptr);
- }
- }
-
- GIVEN("two real image files where the second contains as filesystem formatted files")
- {
- REQUIRE(std::filesystem::exists(image_path_1));
- REQUIRE(std::filesystem::exists(image_path_3));
- REQUIRE_NOTHROW(
- setup_modules_from_img_and_init_vfs({"test_img_module_3", "test_img_module_1"}, {image_path_3, image_path_1}));
-
- auto & vfs = kernel::filesystem::vfs::get();
-
- THEN("cannot unmount a filesystem if files are mounted")
- {
- REQUIRE(vfs.do_mount("/dev/ram16", "/entrance") == kernel::filesystem::vfs::operation_result::success);
- REQUIRE(vfs.do_mount("/entrance/archiv/2024.img", "/enclosures") ==
- kernel::filesystem::vfs::operation_result::success);
-
- REQUIRE(vfs.unmount("/entrance") == kernel::filesystem::vfs::operation_result::unmount_failed);
- REQUIRE(vfs.unmount("/enclosures") == kernel::filesystem::vfs::operation_result::success);
- REQUIRE(vfs.unmount("/entrance") == kernel::filesystem::vfs::operation_result::success);
- }
-
- THEN("can mount filesystem onto the directory that contains it")
- {
- REQUIRE(vfs.do_mount("/dev/ram16", "/entrance") == kernel::filesystem::vfs::operation_result::success);
- REQUIRE(vfs.do_mount("/entrance/archiv/2024.img", "/entrance") ==
- kernel::filesystem::vfs::operation_result::success);
-
- REQUIRE(vfs.unmount("/entrance") == kernel::filesystem::vfs::operation_result::success);
- REQUIRE(vfs.unmount("/entrance") == kernel::filesystem::vfs::operation_result::success);
- }
- }
-
- GIVEN("A real image files, containing symbolic links")
- {
- REQUIRE(std::filesystem::exists(image_path_1));
- REQUIRE_NOTHROW(setup_modules_from_img_and_init_vfs({"test_img_module_1"}, {image_path_1}));
-
- THEN("file can be opened through absolute symbolic link")
- {
- auto & vfs = kernel::filesystem::vfs::get();
- auto info_1 = vfs.open("/symlinks/info_1_absolute");
- REQUIRE(info_1 != nullptr);
- }
-
- THEN("file can be opened through relative symbolic link")
- {
- auto & vfs = kernel::filesystem::vfs::get();
- auto info_1 = vfs.open("/symlinks/info_1_relative");
- REQUIRE(info_1 != nullptr);
- }
-
- THEN("file can be opened through symbolic link pointing absolute to the directory containing the file")
- {
- auto & vfs = kernel::filesystem::vfs::get();
- auto info_1 = vfs.open("/symlinks/information_directory_absolute/info_1.txt");
- REQUIRE(info_1 != nullptr);
- }
-
- THEN("file can be opened through symbolic link pointing relative to the directory containing the file")
- {
- auto & vfs = kernel::filesystem::vfs::get();
- auto info_1 = vfs.open("/symlinks/information_directory_relative/info_1.txt");
- REQUIRE(info_1 != nullptr);
- }
-
- THEN("symbolic link with path traversing back to the root")
- {
- auto & vfs = kernel::filesystem::vfs::get();
- auto info_1 = vfs.open("/symlinks/traverse_back_5_times/information/info_1.txt");
- REQUIRE(info_1 != nullptr);
- }
-
- THEN("symbolic link containing an invalid absolute path is handled correctly")
- {
- auto & vfs = kernel::filesystem::vfs::get();
- auto invalid_symlink = vfs.open("/symlinks/invalid_absolute");
- REQUIRE(invalid_symlink == nullptr);
- }
-
- THEN("symbolic link containing an invalid relative path is handled correctly")
- {
- auto & vfs = kernel::filesystem::vfs::get();
- auto invalid_symlink = vfs.open("/symlinks/invalid_relative");
- REQUIRE(invalid_symlink == nullptr);
- }
-
- THEN("circular symbolic links are detected and handled correctly")
- {
- auto & vfs = kernel::filesystem::vfs::get();
- auto circular_symlink = vfs.open("/symlinks/symloop_a");
- REQUIRE(circular_symlink == nullptr);
- }
- }
-
- GIVEN("A real image file containing as filesystem formatted files and this filesystem contains a symbolic link")
- {
- REQUIRE(std::filesystem::exists(image_path_1));
- REQUIRE_NOTHROW(setup_modules_from_img_and_init_vfs({"test_img_module_1"}, {image_path_1}));
-
- auto & vfs = kernel::filesystem::vfs::get();
- vfs.do_mount("/archiv/2024.img", "/information");
-
- THEN("file can be opened through symbolic link pointing to the parent filesystem")
- {
- auto closed_file = vfs.open("/information/symlinks/traverse_back_twice/closed.txt");
- REQUIRE(closed_file != nullptr);
- }
- }
-
- GIVEN("Two real images, one containing a symbolic link leaving and reentering filesystem again")
- {
- REQUIRE(std::filesystem::exists(image_path_1));
- REQUIRE(std::filesystem::exists(image_path_2));
- REQUIRE_NOTHROW(
- setup_modules_from_img_and_init_vfs({"test_img_module_1", "test_img_module_2"}, {image_path_1, image_path_2}));
-
- auto & vfs = kernel::filesystem::vfs::get();
- vfs.do_mount("/dev/ram16", "/information");
-
- THEN("file can be opened through symbolic link pointing to the parent filesystem and back into the mounted "
- "filesystem again")
- {
- auto monkey_1 = vfs.open("/information/symlinks/leave_and_reenter_mount/monkey_1.txt");
- REQUIRE(monkey_1 != nullptr);
- }
- }
-
- GIVEN("One real image containing a very long symbolic link")
- {
- REQUIRE(std::filesystem::exists(image_path_3));
- REQUIRE_NOTHROW(setup_modules_from_img_and_init_vfs({"test_img_module_3"}, {image_path_3}));
-
- auto & vfs = kernel::filesystem::vfs::get();
-
- THEN("file can be opened through symbolic link with a long path")
- {
- auto fish_30 = vfs.open("/symlinks/very_long_symlink");
- REQUIRE(fish_30 != nullptr);
- }
- }
-
- GIVEN("One real image containing a valid symbolic link chain")
- {
- REQUIRE(std::filesystem::exists(image_path_3));
- REQUIRE_NOTHROW(setup_modules_from_img_and_init_vfs({"test_img_module_3"}, {image_path_3}));
-
- auto & vfs = kernel::filesystem::vfs::get();
-
- THEN("file can be opened through symbolic link chain")
- {
- auto map = vfs.open("/symlinks/symlink_chain_1/map.txt");
- REQUIRE(map != nullptr);
- }
- }
-}
diff --git a/kernel/src/main.cpp b/kernel/src/main.cpp
deleted file mode 100644
index 8dc13490..00000000
--- a/kernel/src/main.cpp
+++ /dev/null
@@ -1,152 +0,0 @@
-#include "kernel/filesystem/type_registry.hpp"
-#include <kernel/devices/storage/management.hpp>
-#include <kernel/filesystem/open_file_table.hpp>
-#include <kernel/filesystem/vfs.hpp>
-#include <kernel/memory.hpp>
-
-#include <kapi/boot_modules.hpp>
-#include <kapi/cio.hpp>
-#include <kapi/cpu.hpp>
-#include <kapi/devices.hpp>
-#include <kapi/filesystem.hpp>
-#include <kapi/interrupts.hpp>
-#include <kapi/memory.hpp>
-#include <kapi/system.hpp>
-
-#include <kstd/format>
-#include <kstd/print>
-#include <kstd/units>
-#include <kstd/vector>
-
-#include <cstddef>
-#include <string_view>
-
-using namespace kstd::units_literals;
-
-auto run_demo() -> void
-{
- // 1) open a file
- kstd::println("attempting to open /entrance/tickets.txt");
- auto fd_1 = kapi::filesystem::open("/entrance/tickets.txt");
- if (fd_1 == -1)
- {
- kapi::system::panic("demo failed");
- }
- else
- {
- kstd::println("--> successfully opened /entrance/tickets.txt with file descriptor {}", fd_1);
- }
-
- // 2) read from the file
- kstd::vector<std::byte> buffer_1{10};
- auto bytes_read = kapi::filesystem::read(fd_1, buffer_1.data(), buffer_1.size());
- auto buffer_as_str = std::string_view{reinterpret_cast<char *>(buffer_1.data()), static_cast<size_t>(bytes_read)};
- kstd::println("--> read {} bytes from /entrance/tickets.txt: {}", bytes_read, buffer_as_str);
- kstd::println("");
-
- // 3) show that /entrance/information/info_1.txt is not accessible before mounting
- kstd::println("attempting to open /entrance/information/info_1.txt before mounting");
- auto fd_before_mount = kapi::filesystem::open("/entrance/information/info_1.txt");
- if (fd_before_mount == -1)
- {
- kstd::println("--> as expected the file could not be opened before mounting");
- }
-
- // 4) mount a new filesystem on top of /entrance
- kstd::println("mount /dev/ram16 to /entrance");
- if (kapi::filesystem::mount("/dev/ram16", "/entrance") == 0)
- {
- kstd::println("--> successfully mounted /dev/ram16 to /entrance");
- }
- else
- {
- kapi::system::panic("demo failed");
- }
- kstd::println("");
-
- // 5) open a file from the new filesystem
- kstd::println("attempting to open /entrance/information/info_1.txt");
- auto fd_2 = kapi::filesystem::open("/entrance/information/info_1.txt");
- if (fd_2 != -1)
- {
- kstd::println("--> successfully opened /entrance/information/info_1.txt with file descriptor {}", fd_2);
- }
- else
- {
- kapi::system::panic("demo failed");
- }
-
- // 6) read from the new file
- kstd::vector<std::byte> buffer_2{10};
- bytes_read = kapi::filesystem::read(fd_2, buffer_2.data(), buffer_2.size());
- buffer_as_str = std::string_view{reinterpret_cast<char *>(buffer_2.data()), static_cast<size_t>(bytes_read)};
- kstd::println("--> read {} bytes from /entrance/information/info_1.txt: {} ", bytes_read, buffer_as_str);
-
- // 7) open device as file
- kstd::println("attempting to open /dev/ram32 as a file");
- auto fd_3 = kapi::filesystem::open("/dev/ram32");
- if (fd_3 != -1)
- {
- kstd::println("--> successfully opened /dev/ram32 as a file with file descriptor {}", fd_3);
- }
- else
- {
- kapi::system::panic("demo failed");
- }
-
- // 8) read from the device file
- kstd::vector<std::byte> buffer_3{2};
- bytes_read = kapi::filesystem::read(fd_3, buffer_3.data(), buffer_3.size());
- kstd::println("--> read {} bytes from /dev/ram32: {::#04x} ", bytes_read, buffer_3);
-
- // 9) write to the device file
- auto const default_buffer_value = std::byte{0xAA};
- kstd::vector<std::byte> write_buffer{default_buffer_value, default_buffer_value};
- auto bytes_written = kapi::filesystem::write(fd_3, write_buffer.data(), write_buffer.size());
- kstd::println("--> written {} bytes to /dev/ram32: {::#04x}", bytes_written, write_buffer);
-
- // 10) do memory dump to show that the write to the device file had an effect
-}
-
-auto main() -> int
-{
- kapi::cio::init();
- kstd::println("[OS] IO subsystem initialized.");
-
- kapi::cpu::init();
-
- kapi::memory::init();
- kernel::memory::init_heap(kapi::memory::heap_base);
- kapi::system::memory_initialized();
- kapi::memory::init_mmio(kapi::memory::mmio_base, 1_GiB / kapi::memory::page::size);
- kstd::println("[OS] Memory subsystem initialized.");
-
- kapi::devices::init();
- kstd::println("[OS] System root bus initialized.");
-
- kapi::devices::init_platform_devices();
- kstd::println("[OS] Platform devices initialized.");
-
- kapi::interrupts::enable();
- kstd::println("[OS] Interrupts enabled.");
-
- kapi::boot_modules::init();
- kstd::println("[OS] Boot module registry initialized.");
-
- kernel::devices::storage::management::init();
- kstd::println("[OS] Storage management initialized.");
-
- kernel::filesystem::open_file_table::init();
- kstd::println("[OS] Global open file table initialized.");
-
- kernel::filesystem::type_registry::init();
- kstd::println("[OS] Builtin filesystems registered.");
-
- kernel::filesystem::vfs::init();
- kstd::println("[OS] Virtual filesystem initialized.");
-
- // TODO BA-FS26 remove demo code?
- // run_demo();
-
- kapi::system::panic("Returning from kernel main!");
-}
diff --git a/kernel/src/memory.cpp b/kernel/src/memory.cpp
deleted file mode 100644
index 6a85c0e7..00000000
--- a/kernel/src/memory.cpp
+++ /dev/null
@@ -1,61 +0,0 @@
-#include <kernel/memory.hpp>
-
-#include <kernel/memory/block_list_allocator.hpp>
-#include <kernel/memory/heap_allocator.hpp>
-
-#include <kapi/memory.hpp>
-#include <kapi/system.hpp>
-
-#include <kstd/print>
-#include <kstd/units>
-
-#include <atomic>
-#include <optional>
-
-namespace kernel::memory
-{
-
- namespace
- {
- struct null_allocator : heap_allocator
- {
- null_allocator static instance;
-
- [[nodiscard]] auto allocate(kstd::units::bytes, kstd::units::bytes) noexcept -> void * override
- {
- kstd::print(kstd::print_sink::stderr, "Tried to allocate memory without an active heap!");
- return nullptr;
- }
-
- auto deallocate(void *) noexcept -> void override
- {
- kstd::print(kstd::print_sink::stderr, "Tried to deallocate memory without an active heap!");
- }
- };
-
- constinit null_allocator null_allocator::instance{};
-
- auto constinit active_heap_allocator = std::optional<heap_allocator *>{&null_allocator::instance};
- auto constinit basic_allocator = std::optional<block_list_allocator>{};
- } // namespace
-
- auto get_heap_allocator() -> heap_allocator &
- {
- return *active_heap_allocator.value();
- }
-
- auto init_heap(kapi::memory::linear_address base) -> void
- {
- auto static constinit is_initialized = std::atomic_flag{};
-
- if (is_initialized.test_and_set())
- {
- kapi::system::panic("[OS:MEM] The heap has already been initialized.");
- }
-
- auto & instance = basic_allocator.emplace(base);
- active_heap_allocator = &instance;
- kstd::println("[OS:MEM] Heap initialized. Dynamic memory available.");
- }
-
-} // namespace kernel::memory \ No newline at end of file
diff --git a/kernel/src/memory/bitmap_allocator.cpp b/kernel/src/memory/bitmap_allocator.cpp
deleted file mode 100644
index 240e2afe..00000000
--- a/kernel/src/memory/bitmap_allocator.cpp
+++ /dev/null
@@ -1,106 +0,0 @@
-#include <kernel/memory/bitmap_allocator.hpp>
-
-#include <kapi/memory.hpp>
-
-#include <algorithm>
-#include <cstddef>
-#include <cstdint>
-#include <optional>
-#include <ranges>
-#include <span>
-#include <utility>
-
-namespace kernel::memory
-{
-
- bitmap_frame_allocator::bitmap_frame_allocator(std::span<std::uint64_t> storage, std::size_t frame_count) noexcept
- : m_bitmap{storage}
- , m_frame_count{frame_count}
- , m_last_index{}
- {
- constexpr auto bits_per_word = 64uz;
- auto to_fill = (frame_count + bits_per_word - 1) / bits_per_word;
- std::ranges::fill(std::views::take(m_bitmap, to_fill), ~0uz);
- }
-
- auto bitmap_frame_allocator::allocate_many(std::size_t count) noexcept
- -> std::optional<std::pair<kapi::memory::frame, std::size_t>>
- {
- if (count == 0)
- {
- return std::nullopt;
- }
-
- auto free_count = 0uz;
- auto first_free = 0uz;
-
- for (auto i = 0uz; i < m_frame_count; ++i)
- {
- auto const current = (m_last_index + i) % m_frame_count;
- if (!test(current))
- {
- if (free_count == 0)
- {
- first_free = current;
- }
-
- ++free_count;
-
- if (free_count == count)
- {
- for (auto j = 0uz; j < count; ++j)
- {
- set(first_free + j);
- }
- m_last_index = first_free + count;
- return std::make_pair(kapi::memory::frame{first_free}, count);
- }
- }
- else
- {
- free_count = 0;
- }
- }
-
- return std::nullopt;
- }
-
- auto bitmap_frame_allocator::release_many(std::pair<kapi::memory::frame, std::size_t> frame_set) -> void
- {
- auto const [start, count] = frame_set;
- for (auto i = 0uz; i < count; ++i)
- {
- clear(start.number() + i);
- }
- }
-
- auto bitmap_frame_allocator::mark_used(kapi::memory::frame frame) -> void
- {
- set(frame.number());
- }
-
- auto bitmap_frame_allocator::test(std::size_t index) const noexcept -> bool
- {
- constexpr auto bits_per_word = 64uz;
- auto entry_entry = index / bits_per_word;
- auto entry_offset = index % bits_per_word;
- return (m_bitmap[entry_entry] & (1uz << entry_offset));
- }
-
- auto bitmap_frame_allocator::set(std::size_t index) noexcept -> void
- {
- constexpr auto bits_per_word = 64uz;
- auto entry_entry = index / bits_per_word;
- auto entry_offset = index % bits_per_word;
- m_bitmap[entry_entry] |= (1uz << entry_offset);
- }
-
- auto bitmap_frame_allocator::clear(std::size_t index) noexcept -> void
- {
- constexpr auto bits_per_word = 64uz;
- auto entry_entry = index / bits_per_word;
- auto entry_offset = index % bits_per_word;
- m_bitmap[entry_entry] &= ~(1uz << entry_offset);
- }
-
-} // namespace kernel::memory \ No newline at end of file
diff --git a/kernel/src/memory/bitmap_allocator.tests.cpp b/kernel/src/memory/bitmap_allocator.tests.cpp
deleted file mode 100644
index 05d11a33..00000000
--- a/kernel/src/memory/bitmap_allocator.tests.cpp
+++ /dev/null
@@ -1,288 +0,0 @@
-#include <kernel/memory/bitmap_allocator.hpp>
-
-#include <kapi/memory.hpp>
-
-#include <catch2/catch_test_macros.hpp>
-#include <catch2/matchers/catch_matchers.hpp>
-#include <catch2/matchers/catch_matchers_range_equals.hpp>
-
-#include <cstdint>
-#include <limits>
-#include <ranges>
-#include <span>
-#include <vector>
-
-constexpr auto all_bits_set = std::numeric_limits<std::uint64_t>::max();
-constexpr auto available_frames = 1024uz;
-
-SCENARIO("Bitmap allocator construction and initialization", "[memory][bitmap_allocator]")
-{
- GIVEN("A storage region")
- {
- auto storage = std::vector(available_frames / 64, 0uz);
-
- WHEN("constructing the allocator with 0 frames")
- {
- auto allocator = kernel::memory::bitmap_frame_allocator{std::span(storage), 0};
-
- THEN("the storage region is not modified")
- {
- REQUIRE_THAT(storage, Catch::Matchers::RangeEquals(std::vector(16, 0uz)));
- }
- }
-
- WHEN("constructing with 1 frame")
- {
- auto allocator = kernel::memory::bitmap_frame_allocator{std::span(storage), 1};
-
- THEN("the first word of the storage region is set to all ones")
- {
- REQUIRE_THAT(std::views::take(storage, 1), Catch::Matchers::RangeEquals(std::vector(1, all_bits_set)));
- }
-
- THEN("the rest of the storage region is not modified")
- {
- REQUIRE_THAT(std::views::drop(storage, 1), Catch::Matchers::RangeEquals(std::vector(15, 0uz)));
- }
- }
-
- WHEN("constructing with 64 frames")
- {
- auto allocator = kernel::memory::bitmap_frame_allocator{std::span(storage), 64};
-
- THEN("the first word of the storage region is set to all ones")
- {
- REQUIRE_THAT(std::views::take(storage, 1), Catch::Matchers::RangeEquals(std::vector(1, all_bits_set)));
- }
-
- THEN("the rest of the storage region is not modified")
- {
- REQUIRE_THAT(std::views::drop(storage, 1), Catch::Matchers::RangeEquals(std::vector(15, 0uz)));
- }
- }
-
- WHEN("constructing with all available frames")
- {
- auto allocator = kernel::memory::bitmap_frame_allocator{std::span(storage), available_frames};
-
- THEN("the storage region is filled with all ones")
- {
- REQUIRE_THAT(storage, Catch::Matchers::RangeEquals(std::vector(16, all_bits_set)));
- }
- }
-
- WHEN("constructing with half the available frames")
- {
- auto allocator = kernel::memory::bitmap_frame_allocator{std::span(storage), available_frames / 2};
-
- THEN("the first half of the storage region is filled with all ones")
- {
- REQUIRE_THAT(std::views::take(storage, (available_frames / 2) / 64),
- Catch::Matchers::RangeEquals(std::vector((available_frames / 2) / 64, all_bits_set)));
- }
-
- THEN("the second half of the storage region is filled with all zeros")
- {
- REQUIRE_THAT(std::views::drop(storage, (available_frames / 2) / 64),
- Catch::Matchers::RangeEquals(std::vector((available_frames / 2) / 64, 0uz)));
- }
- }
- }
-}
-
-SCENARIO("Bitmap allocator frame allocation", "[memory][bitmap_allocator]")
-{
- GIVEN("A storage region")
- {
- auto storage = std::vector(available_frames / 64, 0uz);
-
- AND_GIVEN("an allocator constructed with all available frames but no free ones")
- {
- auto allocator = kernel::memory::bitmap_frame_allocator{std::span(storage), available_frames};
-
- WHEN("allocating 1 frame")
- {
- auto result = allocator.allocate_many(1);
-
- THEN("the result is empty")
- {
- REQUIRE_FALSE(result.has_value());
- }
- }
- }
-
- AND_GIVEN("an allocator constructed with all available frames but only one free one")
- {
- auto allocator = kernel::memory::bitmap_frame_allocator{std::span(storage), available_frames};
- allocator.release_many({kapi::memory::frame{0}, 1});
-
- WHEN("allocating 1 frame")
- {
- auto result = allocator.allocate_many(1);
-
- THEN("the result is not empty")
- {
- REQUIRE(result.has_value());
- }
-
- THEN("the result contains 1 frame")
- {
- REQUIRE(result->second == 1);
- }
- }
-
- WHEN("allocating more frames than are free")
- {
- auto result = allocator.allocate_many(2);
-
- THEN("the result is empty")
- {
- REQUIRE_FALSE(result.has_value());
- }
-
- AND_WHEN("allocating a single frame")
- {
- auto result = allocator.allocate_many(1);
-
- THEN("the result is not empty")
- {
- REQUIRE(result.has_value());
- }
- }
-
- WHEN("allocating 0 frames")
- {
- auto result = allocator.allocate_many(0);
-
- THEN("the result is empty")
- {
- REQUIRE_FALSE(result.has_value());
- }
- }
- }
- }
-
- AND_GIVEN("an allocator with many single frame holes")
- {
- auto allocator = kernel::memory::bitmap_frame_allocator{std::span(storage), available_frames};
- for (auto i = 0uz; i < available_frames; i += 2)
- {
- allocator.release_many({kapi::memory::frame{i}, 1});
- }
-
- WHEN("allocating 1 frame")
- {
- auto result = allocator.allocate_many(1);
-
- THEN("the result is not empty")
- {
- REQUIRE(result.has_value());
- }
-
- THEN("the result contains 1 frame")
- {
- REQUIRE(result->second == 1);
- }
- }
-
- WHEN("allocating 2 frames")
- {
- auto result = allocator.allocate_many(2);
-
- THEN("the result is empty")
- {
- REQUIRE_FALSE(result.has_value());
- }
- }
- }
-
- AND_GIVEN("and allocator with all frames marked as free")
- {
- auto allocator = kernel::memory::bitmap_frame_allocator{std::span(storage), available_frames};
- allocator.release_many({kapi::memory::frame{0}, available_frames});
-
- WHEN("allocating 1 frame")
- {
- auto result = allocator.allocate_many(1);
-
- THEN("the result is not empty")
- {
- REQUIRE(result.has_value());
- }
-
- THEN("the result contains 1 frame")
- {
- REQUIRE(result->second == 1);
- }
- }
-
- WHEN("allocating multiple frames")
- {
- auto result = allocator.allocate_many(20);
-
- THEN("the result is not empty")
- {
- REQUIRE(result.has_value());
- }
-
- THEN("the result contains 20 frames")
- {
- REQUIRE(result->second == 20);
- }
- }
-
- WHEN("marking all frames as used")
- {
- for (auto i = 0uz; i < available_frames; i++)
- {
- allocator.mark_used(kapi::memory::frame{i});
- }
-
- THEN("the allocator has no free frames")
- {
- REQUIRE_FALSE(allocator.allocate_many(1).has_value());
- }
- }
- }
-
- AND_GIVEN("an allocator with a contiguous block of free frames")
- {
- auto allocator = kernel::memory::bitmap_frame_allocator{std::span(storage), available_frames};
- allocator.release_many({kapi::memory::frame{0}, available_frames});
- for (auto i = 0uz; i < available_frames / 2; i++)
- {
- allocator.mark_used(kapi::memory::frame{i});
- }
-
- WHEN("allocating a single frame")
- {
- auto result = allocator.allocate_many(1);
-
- THEN("the result is not empty")
- {
- REQUIRE(result.has_value());
- }
-
- THEN("the result contains 1 frame")
- {
- REQUIRE(result->second == 1);
- }
- }
-
- WHEN("allocating multiple frames")
- {
- auto result = allocator.allocate_many(20);
-
- THEN("the result is not empty")
- {
- REQUIRE(result.has_value());
- }
-
- THEN("the result contains 20 frames")
- {
- REQUIRE(result->second == 20);
- }
- }
- }
- }
-} \ No newline at end of file
diff --git a/kernel/src/memory/block_list_allocator.cpp b/kernel/src/memory/block_list_allocator.cpp
deleted file mode 100644
index 6e68ada7..00000000
--- a/kernel/src/memory/block_list_allocator.cpp
+++ /dev/null
@@ -1,215 +0,0 @@
-#include <kernel/memory/block_list_allocator.hpp>
-
-#include <kernel/memory/heap_allocator.hpp>
-
-#include <kapi/memory.hpp>
-#include <kapi/system.hpp>
-
-#include <kstd/mutex>
-#include <kstd/units>
-
-#include <bit>
-#include <cstddef>
-#include <cstdint>
-#include <memory>
-
-using namespace kstd::units_literals;
-
-namespace kernel::memory
-{
-
- namespace
- {
- [[nodiscard]] constexpr auto align_up(std::byte * pointer, kstd::units::bytes alignment) noexcept -> std::byte *
- {
- auto const remainder = std::bit_cast<std::uintptr_t>(pointer) % static_cast<std::size_t>(alignment);
- return remainder == 0 ? pointer : pointer + static_cast<std::size_t>(alignment) - remainder;
- }
- } // namespace
-
- block_list_allocator::block_list_allocator(kapi::memory::linear_address base) noexcept
- : heap_allocator{}
- , m_base{base}
- , m_frontier{base}
- , m_block_list{}
- , m_lock{}
- {}
-
- auto block_list_allocator::allocate(kstd::units::bytes size, kstd::units::bytes alignment) noexcept -> void *
- {
- kstd::lock_guard guard{m_lock};
-
- for (auto attempt = 0uz; attempt < 2uz; ++attempt)
- {
- auto current = m_block_list;
- while (current != nullptr)
- {
- if (current->free)
- {
- auto const raw_block = reinterpret_cast<std::byte *>(current);
- auto const unaligned_payload = raw_block + allocated_metadata_size;
- auto const aligned_payload = align_up(unaligned_payload, alignment);
- auto const required_padding = static_cast<kstd::units::bytes>(aligned_payload - unaligned_payload);
- auto const total_required_size = required_padding + allocated_metadata_size + size;
-
- if (current->usable_size >= total_required_size)
- {
- auto const payload_header = aligned_payload - sizeof(block_header *) - sizeof(block_header);
- auto const front_padding = static_cast<kstd::units::bytes>(payload_header - raw_block);
-
- auto payload_block = current;
-
- if (front_padding >= allocated_metadata_size + minimum_allocation_size)
- {
- payload_block = reinterpret_cast<block_header *>(payload_header);
- std::construct_at(payload_block, current->usable_size - front_padding, true, current->next);
-
- if (payload_block->next)
- {
- payload_block->next->prev = payload_block;
- }
-
- current->usable_size = front_padding - allocated_metadata_size;
- current->next = payload_block;
- payload_block->prev = current;
- }
-
- auto const header_size =
- static_cast<kstd::units::bytes>(aligned_payload - reinterpret_cast<std::byte *>(payload_block));
- auto const payload_size = header_size - allocated_metadata_size + size;
- split(payload_block, payload_size, 0_B);
-
- payload_block->free = false;
-
- auto back_pointer = reinterpret_cast<block_header **>(aligned_payload - sizeof(block_header *));
- *back_pointer = payload_block;
-
- return reinterpret_cast<void *>(aligned_payload);
- }
- }
- current = current->next;
- }
-
- auto const search_size = size + alignment;
- if (attempt == 0uz && !expand(search_size))
- {
- return nullptr;
- }
- }
-
- return nullptr;
- }
-
- auto block_list_allocator::deallocate(void * ptr) noexcept -> void
- {
- if (!ptr)
- {
- return;
- }
-
- kstd::lock_guard guard{m_lock};
-
- auto const aligned_payload = reinterpret_cast<std::byte *>(ptr);
- auto back_pointer = reinterpret_cast<block_header **>(aligned_payload - sizeof(block_header *));
- auto block = *back_pointer;
-
- block->free = true;
- coalesce(block);
- }
-
- auto block_list_allocator::expand(kstd::units::bytes size) noexcept -> bool
- {
- auto const total_required_size = size + allocated_metadata_size;
- auto const frames_needed = (total_required_size + kapi::memory::frame::size - 1_B) / kapi::memory::frame::size;
-
- auto const flags = kapi::memory::page_mapper::flags::writable | kapi::memory::page_mapper::flags::supervisor_only |
- kapi::memory::page_mapper::flags::global;
-
- for (auto i = 0uz; i < frames_needed; ++i)
- {
- auto frame = kapi::memory::allocate_frame();
- if (!frame)
- {
- kapi::system::panic("[OS:Heap] OOM when expanding heap.");
- return false;
- }
-
- auto page = kapi::memory::page::containing(m_frontier + i * kapi::memory::page::size);
- kapi::memory::map(page, *frame, flags);
- }
-
- auto block = static_cast<block_header *>(m_frontier);
- std::construct_at(block, frames_needed * kapi::memory::frame::size - allocated_metadata_size, true, nullptr,
- nullptr);
-
- m_frontier += frames_needed * kapi::memory::frame::size;
-
- if (!m_block_list)
- {
- m_block_list = block;
- }
- else
- {
- auto current = m_block_list;
- while (current->next)
- {
- current = current->next;
- }
- current->next = block;
- block->prev = current;
- }
-
- coalesce(block);
- return true;
- }
-
- auto block_list_allocator::coalesce(block_header * block) noexcept -> void
- {
- if (block->next && block->next->free)
- {
- auto follower = block->next;
- block->usable_size += follower->usable_size + allocated_metadata_size;
- block->next = follower->next;
- if (block->next)
- {
- block->next->prev = block;
- }
- std::destroy_at(follower);
- }
-
- if (block->prev && block->prev->free)
- {
- auto leader = block->prev;
- leader->usable_size += block->usable_size + allocated_metadata_size;
- leader->next = block->next;
- if (block->next)
- {
- block->next->prev = leader;
- }
- std::destroy_at(block);
- }
- }
-
- auto block_list_allocator::split(block_header * block, kstd::units::bytes size, kstd::units::bytes padding) noexcept
- -> void
- {
- auto const new_block_size = size + padding;
-
- if (block->usable_size > new_block_size + allocated_metadata_size + minimum_allocation_size)
- {
- auto raw_block = reinterpret_cast<std::byte *>(block);
- auto new_block = reinterpret_cast<block_header *>(raw_block + allocated_metadata_size + new_block_size);
- std::construct_at(new_block, block->usable_size - new_block_size - allocated_metadata_size, true, block->next,
- block);
-
- if (new_block->next)
- {
- new_block->next->prev = new_block;
- }
-
- block->usable_size = new_block_size;
- block->next = new_block;
- }
- }
-
-} // namespace kernel::memory \ No newline at end of file
diff --git a/kernel/src/memory/block_list_allocator.tests.cpp b/kernel/src/memory/block_list_allocator.tests.cpp
deleted file mode 100644
index c5f84c52..00000000
--- a/kernel/src/memory/block_list_allocator.tests.cpp
+++ /dev/null
@@ -1,85 +0,0 @@
-#include <kernel/memory/block_list_allocator.hpp>
-
-#include <kernel/test_support/memory.hpp>
-
-#include <kapi/memory.hpp>
-
-#include <kstd/units>
-
-#include <catch2/catch_test_macros.hpp>
-
-#include <cstddef>
-
-using namespace kstd::units_literals;
-
-SCENARIO("Block List Allocator Operations", "[memory][allocator]")
-{
- GIVEN("A newly initialized block list allocator mapped via the test sandbox")
- {
- kernel::tests::memory::deinit();
- kapi::memory::init();
-
- auto sandbox_base = kernel::tests::memory::virtual_base();
- kernel::memory::block_list_allocator allocator{sandbox_base};
-
- WHEN("a basic allocation request is made")
- {
- void * ptr = allocator.allocate(128_B, 8_B);
-
- THEN("a valid, non-null pointer is returned")
- {
- REQUIRE(ptr != nullptr);
- }
-
- AND_THEN("the returned memory is writeable without causing segmentation faults")
- {
- auto byte_ptr = static_cast<std::byte *>(ptr);
- byte_ptr[0] = std::byte{0xDE};
- byte_ptr[127] = std::byte{0xAD};
- REQUIRE(byte_ptr[0] == std::byte{0xDE});
- REQUIRE(byte_ptr[127] == std::byte{0xAD});
- }
-
- allocator.deallocate(ptr);
- }
-
- WHEN("multiple allocations are made sequentially")
- {
- void * ptr1 = allocator.allocate(64_B, 8_B);
- void * ptr2 = allocator.allocate(64_B, 8_B);
- void * ptr3 = allocator.allocate(1_KiB, 16_B);
-
- THEN("they return distinct, non-overlapping memory blocks")
- {
- REQUIRE(ptr1 != nullptr);
- REQUIRE(ptr2 != nullptr);
- REQUIRE(ptr3 != nullptr);
- REQUIRE(ptr1 != ptr2);
- REQUIRE(ptr2 != ptr3);
- REQUIRE(ptr1 != ptr3);
- }
-
- allocator.deallocate(ptr1);
- allocator.deallocate(ptr2);
- allocator.deallocate(ptr3);
- }
-
- WHEN("a block is allocated and then completely freed")
- {
- void * original_ptr = allocator.allocate(512_B, 16_B);
- allocator.deallocate(original_ptr);
-
- AND_WHEN("a new allocation of equal or smaller size is requested")
- {
- void * new_ptr = allocator.allocate(128_B, 16_B);
-
- THEN("the allocator actively reuses the coalesced space")
- {
- REQUIRE(new_ptr == original_ptr);
- }
-
- allocator.deallocate(new_ptr);
- }
- }
- }
-}
diff --git a/kernel/src/memory/mmio_allocator.cpp b/kernel/src/memory/mmio_allocator.cpp
deleted file mode 100644
index ba23dbde..00000000
--- a/kernel/src/memory/mmio_allocator.cpp
+++ /dev/null
@@ -1,111 +0,0 @@
-#include <kernel/memory/mmio_allocator.hpp>
-
-#include <kapi/memory.hpp>
-#include <kapi/system.hpp>
-
-#include <kstd/allocator>
-
-#include <cstddef>
-#include <memory>
-#include <utility>
-
-namespace kernel::memory
-{
-
- mmio_allocator::mmio_allocator(kapi::memory::linear_address base, std::size_t pages)
- : m_head{make_node(base, pages, nullptr, nullptr, true)}
- {}
-
- auto mmio_allocator::allocate(std::size_t count) -> kapi::memory::linear_address
- {
- if (count == 0 || !m_head)
- {
- return {};
- }
-
- auto current = m_head;
- while (current)
- {
- if (current->is_free && current->page_count >= count)
- {
- if (current->page_count > count)
- {
- auto new_base = current->base + (count * kapi::memory::page::size);
- auto split_node = make_node(new_base, current->page_count - count, std::move(current->next), current, true);
-
- if (current->next)
- {
- current->next->previous = split_node;
- }
- current->next = split_node;
- current->page_count = count;
- }
-
- current->is_free = false;
- return current->base;
- }
- current = current->next;
- }
-
- kapi::system::panic("[OS:MEM] MMIO alloctor out of memory!");
- return {};
- }
-
- auto mmio_allocator::release(kapi::memory::linear_address base) -> void
- {
- auto current = m_head;
-
- while (current)
- {
- if (current->base == base && !current->is_free)
- {
- current->is_free = true;
-
- if (current->next && current->next->is_free)
- {
- auto removed = current->next;
- current->page_count += removed->page_count;
- current->next = removed->next;
- if (current->next)
- {
- current->next->previous = current;
- }
- destroy_node(removed);
- }
-
- if (current->previous && current->previous->is_free)
- {
- auto removed = current;
- removed->previous->page_count += removed->page_count;
- removed->previous->next = removed->next;
- if (removed->next)
- {
- removed->next->previous = removed->previous;
- }
- destroy_node(removed);
- }
- return;
- }
- current = current->next;
- }
- }
-
- auto mmio_allocator::make_node(kapi::memory::linear_address base, std::size_t page_count, node * next,
- node * previous, bool is_free) -> node *
- {
- using traits = std::allocator_traits<kstd::allocator<node>>;
-
- auto new_node = traits::allocate(m_allocator, 1);
- traits::construct(m_allocator, new_node, base, page_count, next, previous, is_free);
- return new_node;
- }
-
- auto mmio_allocator::destroy_node(node * instance) -> void
- {
- using traits = std::allocator_traits<kstd::allocator<node>>;
-
- traits::destroy(m_allocator, instance);
- traits::deallocate(m_allocator, instance, 1);
- }
-
-} // namespace kernel::memory
diff --git a/kernel/src/memory/operators.cpp b/kernel/src/memory/operators.cpp
deleted file mode 100644
index 5673d680..00000000
--- a/kernel/src/memory/operators.cpp
+++ /dev/null
@@ -1,102 +0,0 @@
-#include <kernel/memory.hpp>
-
-#include <kapi/system.hpp>
-
-#include <kstd/units>
-
-#include <cstddef>
-#include <new>
-
-[[nodiscard]] auto operator new(std::size_t size, std::align_val_t alignment, std::nothrow_t const &) noexcept -> void *
-{
- auto & allocator = kernel::memory::get_heap_allocator();
- return allocator.allocate(static_cast<kstd::units::bytes>(size),
- static_cast<kstd::units::bytes>(static_cast<std::size_t>(alignment)));
-}
-
-[[nodiscard]] auto operator new(std::size_t size, std::align_val_t alignment) -> void *
-{
- auto pointer = operator new(size, alignment, std::nothrow);
-
- if (pointer == nullptr)
- {
- kapi::system::panic("[OS:Heap] Out of memory!");
- }
-
- return pointer;
-}
-
-[[nodiscard]] auto operator new(std::size_t size, std::nothrow_t const &) noexcept -> void *
-{
- return operator new(size, std::align_val_t{__STDCPP_DEFAULT_NEW_ALIGNMENT__}, std::nothrow);
-}
-
-[[nodiscard]] auto operator new(std::size_t size) -> void *
-{
- return operator new(size, std::align_val_t{__STDCPP_DEFAULT_NEW_ALIGNMENT__});
-}
-
-[[nodiscard]] auto operator new[](std::size_t size, std::align_val_t alignment, std::nothrow_t const &) noexcept
- -> void *
-{
- return operator new(size, alignment, std::nothrow);
-}
-
-[[nodiscard]] auto operator new[](std::size_t size, std::align_val_t alignment) -> void *
-{
- return operator new(size, alignment);
-}
-
-[[nodiscard]] auto operator new[](std::size_t size, std::nothrow_t const &) noexcept -> void *
-{
- return ::operator new(size);
-}
-
-[[nodiscard]] auto operator new[](std::size_t size) -> void *
-{
- return ::operator new(size);
-}
-
-auto operator delete(void * pointer) noexcept -> void
-{
- if (pointer != nullptr)
- {
- auto & allocator = kernel::memory::get_heap_allocator();
- allocator.deallocate(pointer);
- }
-}
-
-auto operator delete(void * pointer, std::size_t) noexcept -> void
-{
- ::operator delete(pointer);
-}
-
-auto operator delete(void * pointer, std::align_val_t) noexcept -> void
-{
- ::operator delete(pointer);
-}
-
-auto operator delete(void * pointer, std::size_t size, std::align_val_t) noexcept -> void
-{
- ::operator delete(pointer, size);
-}
-
-auto operator delete[](void * pointer) noexcept -> void
-{
- ::operator delete(pointer);
-}
-
-auto operator delete[](void * pointer, std::size_t size) noexcept -> void
-{
- ::operator delete(pointer, size);
-}
-
-auto operator delete[](void * pointer, std::align_val_t) noexcept -> void
-{
- ::operator delete(pointer);
-}
-
-auto operator delete[](void * pointer, std::size_t size, std::align_val_t) noexcept -> void
-{
- ::operator delete(pointer, size);
-}
diff --git a/kernel/src/test_support/devices/block_device.cpp b/kernel/src/test_support/devices/block_device.cpp
deleted file mode 100644
index 9a9e544d..00000000
--- a/kernel/src/test_support/devices/block_device.cpp
+++ /dev/null
@@ -1,61 +0,0 @@
-#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
deleted file mode 100644
index 3806654f..00000000
--- a/kernel/src/test_support/devices/character_device.cpp
+++ /dev/null
@@ -1,19 +0,0 @@
-#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
deleted file mode 100644
index 52b6efe7..00000000
--- a/kernel/src/test_support/filesystem/ext2.cpp
+++ /dev/null
@@ -1,68 +0,0 @@
-#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
deleted file mode 100644
index ec706077..00000000
--- a/kernel/src/test_support/filesystem/filesystem.cpp
+++ /dev/null
@@ -1,17 +0,0 @@
-#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
deleted file mode 100644
index 0c8d9563..00000000
--- a/kernel/src/test_support/filesystem/inode.cpp
+++ /dev/null
@@ -1,23 +0,0 @@
-#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
deleted file mode 100644
index aabaaceb..00000000
--- a/kernel/src/test_support/filesystem/storage_boot_module_fixture.cpp
+++ /dev/null
@@ -1,139 +0,0 @@
-#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
deleted file mode 100644
index 02ccfec3..00000000
--- a/kernel/src/test_support/filesystem/storage_boot_module_vfs_fixture.cpp
+++ /dev/null
@@ -1,31 +0,0 @@
-#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
deleted file mode 120000
index 718a2275..00000000
--- a/kernel/src/test_support/filesystem/test_assets/README.md
+++ /dev/null
@@ -1 +0,0 @@
-/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
deleted file mode 100644
index a5202ca3..00000000
--- a/kernel/src/test_support/filesystem/test_assets/ext2_1KB_fs.img
+++ /dev/null
@@ -1,3 +0,0 @@
-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
deleted file mode 100644
index 7f297f07..00000000
--- a/kernel/src/test_support/filesystem/test_assets/ext2_2KB_fs.img
+++ /dev/null
@@ -1,3 +0,0 @@
-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
deleted file mode 100644
index c3f6dafb..00000000
--- a/kernel/src/test_support/filesystem/test_assets/ext2_4KB_fs.img
+++ /dev/null
@@ -1,3 +0,0 @@
-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
deleted file mode 100644
index 98bc99d7..00000000
--- a/kernel/src/test_support/kapi/cio.cpp
+++ /dev/null
@@ -1,54 +0,0 @@
-#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
deleted file mode 100644
index 5d956331..00000000
--- a/kernel/src/test_support/kapi/cpu.cpp
+++ /dev/null
@@ -1,52 +0,0 @@
-#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
deleted file mode 100644
index 00772669..00000000
--- a/kernel/src/test_support/kapi/interrupts.cpp
+++ /dev/null
@@ -1,11 +0,0 @@
-#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
deleted file mode 100644
index 7fc95cb0..00000000
--- a/kernel/src/test_support/kapi/memory.cpp
+++ /dev/null
@@ -1,74 +0,0 @@
-#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
deleted file mode 100644
index 04d875bd..00000000
--- a/kernel/src/test_support/log_buffer.cpp
+++ /dev/null
@@ -1,33 +0,0 @@
-#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
deleted file mode 100644
index 45fb4bc8..00000000
--- a/kernel/src/test_support/output_device.cpp
+++ /dev/null
@@ -1,28 +0,0 @@
-#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
deleted file mode 100644
index 3d50ff1a..00000000
--- a/kernel/src/test_support/page_mapper.cpp
+++ /dev/null
@@ -1,70 +0,0 @@
-#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
deleted file mode 100644
index 074e6b10..00000000
--- a/kernel/src/test_support/simulated_memory.cpp
+++ /dev/null
@@ -1,106 +0,0 @@
-#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
deleted file mode 100644
index 6bb7537c..00000000
--- a/kernel/src/test_support/state_reset_listener.cpp
+++ /dev/null
@@ -1,48 +0,0 @@
-#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