From b334a8494bef50c5b90adc1f101464fc8c4c971a Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Thu, 23 Jul 2026 23:55:28 +0200 Subject: kernel: port ram disk to new driver architecture --- kernel/CMakeLists.txt | 4 +- kernel/kapi/boot_module/bus.cpp | 102 ++++++++++++++ kernel/kernel/devices/storage.cpp | 12 +- .../kernel/devices/storage/ram_disk/controller.cpp | 38 ------ .../kernel/devices/storage/ram_disk/controller.hpp | 31 ----- .../devices/storage/ram_disk/controller.tests.cpp | 82 ----------- kernel/kernel/devices/storage/ram_disk/device.cpp | 95 ------------- kernel/kernel/devices/storage/ram_disk/device.hpp | 60 -------- .../devices/storage/ram_disk/device.tests.cpp | 117 ---------------- kernel/kernel/devices/storage/ram_disk/driver.cpp | 152 +++++++++++++++++++++ kernel/kernel/devices/storage/ram_disk/driver.hpp | 39 ++++++ 11 files changed, 304 insertions(+), 428 deletions(-) create mode 100644 kernel/kapi/boot_module/bus.cpp delete mode 100644 kernel/kernel/devices/storage/ram_disk/controller.cpp delete mode 100644 kernel/kernel/devices/storage/ram_disk/controller.hpp delete mode 100644 kernel/kernel/devices/storage/ram_disk/controller.tests.cpp delete mode 100644 kernel/kernel/devices/storage/ram_disk/device.cpp delete mode 100644 kernel/kernel/devices/storage/ram_disk/device.hpp delete mode 100644 kernel/kernel/devices/storage/ram_disk/device.tests.cpp create mode 100644 kernel/kernel/devices/storage/ram_disk/driver.cpp create mode 100644 kernel/kernel/devices/storage/ram_disk/driver.hpp (limited to 'kernel') diff --git a/kernel/CMakeLists.txt b/kernel/CMakeLists.txt index d3e0c015..72283587 100644 --- a/kernel/CMakeLists.txt +++ b/kernel/CMakeLists.txt @@ -8,6 +8,7 @@ add_library("kernel::lib" ALIAS "kernel_lib") target_sources("kernel_lib" PRIVATE # Kernel-defined KAPI Implementation "kapi/acpi.cpp" + "kapi/boot_module/bus.cpp" "kapi/boot_modules.cpp" "kapi/cio.cpp" "kapi/cpu.cpp" @@ -43,8 +44,7 @@ target_sources("kernel_lib" PRIVATE # Storage Device Subsystem "kernel/devices/storage.cpp" - "kernel/devices/storage/ram_disk/controller.cpp" - "kernel/devices/storage/ram_disk/device.cpp" + "kernel/devices/storage/ram_disk/driver.cpp" # Filesystem Subsystem "kernel/filesystem/dentry.cpp" diff --git a/kernel/kapi/boot_module/bus.cpp b/kernel/kapi/boot_module/bus.cpp new file mode 100644 index 00000000..b917866c --- /dev/null +++ b/kernel/kapi/boot_module/bus.cpp @@ -0,0 +1,102 @@ +#include + +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +namespace kapi::boot_modules +{ + auto has_parameter(std::string_view cmdline, std::string_view key, std::string_view value) -> bool + { + for (auto token : std::views::split(cmdline, ' ')) + { + auto const text = std::string_view{token}; + auto const equals = text.find('='); + if (equals != std::string_view::npos && text.substr(equals) == key && text.substr(equals + 1) == value) + { + return true; + } + } + return false; + } + + boot_module_device::boot_module_device(std::size_t index, boot_module const & module) + : kapi::devices::device{kstd::format("boot_module{}", index)} + , m_module(module) + {} + + auto boot_module_device::init() -> bool + { + return true; + } + + auto boot_module_device::command_line() const -> std::string_view + { + return m_module.name; + } + + auto boot_module_device::module() const -> boot_modules::boot_module const & + { + return m_module; + } + + auto boot_module_device::query_interface(kapi::devices::interface interface) -> void * + { + if (interface == boot_module_identification::id) + { + return static_cast(this); + } + + return kapi::devices::device::query_interface(interface); + } + + boot_module_bus::boot_module_bus(boot_module_registry const * registry) + : kapi::devices::bus{"boot_modules"} + , m_registry(registry) + {} + + auto boot_module_bus::enumerate(kapi::devices::bus & self) -> void + { + std::size_t index = 0; + + for (auto const & module : *m_registry) + { + self.add_child(kstd::make_shared(index++, module)); + } + } + + auto boot_module_bus::match(kapi::devices::device const & dev, kapi::devices::driver const & drv) const + -> kstd::result + { + auto const * ident = dev.as(); + auto const * claims = drv.as(); + + if (!ident || !claims) + { + return kstd::failure(kapi::devices::driver_match_errc::no_match); + } + + auto const [key, value] = claims->claimed_parameter(); + + if (!has_parameter(ident->command_line(), key, value)) + { + return kstd::failure(kapi::devices::driver_match_errc::no_match); + } + + return 0u; + } + + auto boot_module_bus::protocol() -> kapi::devices::bus_protocol * + { + return this; + } + +} // namespace kapi::boot_modules diff --git a/kernel/kernel/devices/storage.cpp b/kernel/kernel/devices/storage.cpp index d5d6fab7..d5508270 100644 --- a/kernel/kernel/devices/storage.cpp +++ b/kernel/kernel/devices/storage.cpp @@ -1,9 +1,11 @@ #include -#include +#include +#include #include #include +#include #include @@ -11,8 +13,12 @@ namespace kernel::devices::storage { auto init() -> void { - kapi::devices::get_root_bus()->add_child( - kstd::make_shared(&kapi::boot_modules::get_boot_module_registry())); + kapi::devices::driver_registry::get().add(kstd::make_shared()); + + auto modules_bus = + kstd::make_shared(&kapi::boot_modules::get_boot_module_registry()); + kapi::devices::get_root_bus()->add_child(modules_bus); + modules_bus->enumerate(*modules_bus); } auto determine_boot_device() -> kstd::shared_ptr diff --git a/kernel/kernel/devices/storage/ram_disk/controller.cpp b/kernel/kernel/devices/storage/ram_disk/controller.cpp deleted file mode 100644 index 7550860e..00000000 --- a/kernel/kernel/devices/storage/ram_disk/controller.cpp +++ /dev/null @@ -1,38 +0,0 @@ - -#include - -#include - -#include -#include -#include - -#include -#include - -namespace kernel::devices::storage::ram_disk -{ - controller::controller(kapi::boot_modules::boot_module_registry const * registry) - : kapi::devices::bus{"ram_disk"} - , m_boot_module_registry(registry) - {} - - auto controller::enumerate_old() -> bool - { - size_t current_device_index = 0; - - std::ranges::for_each(*m_boot_module_registry, [this, ¤t_device_index](auto const & module) { - auto const disk = kstd::make_shared(module, current_device_index++); - - if (auto published = kapi::devices::publish_interface(disk, disk->name()); - !published) - { - kapi::system::panic("[DEV:RD] Failed to publish block device interface of '{}'", disk->name()); - } - - add_child(std::move(disk)); - }); - - return true; - } -} // namespace kernel::devices::storage::ram_disk \ No newline at end of file diff --git a/kernel/kernel/devices/storage/ram_disk/controller.hpp b/kernel/kernel/devices/storage/ram_disk/controller.hpp deleted file mode 100644 index 165fbdbd..00000000 --- a/kernel/kernel/devices/storage/ram_disk/controller.hpp +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef TEACH_OS_KERNEL_DEVICES_RAM_DISK_CONTROLLER_HPP -#define TEACH_OS_KERNEL_DEVICES_RAM_DISK_CONTROLLER_HPP - -#include -#include - -namespace kernel::devices::storage::ram_disk -{ - /** - * @brief Storage controller that exposes boot modules as RAM-disk devices. - */ - struct controller : kapi::devices::bus - { - /** - * @brief Create a RAM-disk controller. - * @param registry Boot module registry as device source. - */ - explicit controller(kapi::boot_modules::boot_module_registry const * registry); - - protected: - /** - * @brief Probe boot modules and create RAM-disk devices. - */ - auto enumerate_old() -> bool override; - - private: - kapi::boot_modules::boot_module_registry const * m_boot_module_registry; - }; -} // namespace kernel::devices::storage::ram_disk - -#endif \ No newline at end of file diff --git a/kernel/kernel/devices/storage/ram_disk/controller.tests.cpp b/kernel/kernel/devices/storage/ram_disk/controller.tests.cpp deleted file mode 100644 index 6393043b..00000000 --- a/kernel/kernel/devices/storage/ram_disk/controller.tests.cpp +++ /dev/null @@ -1,82 +0,0 @@ -#include - -#include -#include -#include - -#include - -#include - -#include -#include - -SCENARIO("The RAM disk controller attaches its devices to the device tree", "[devices][storage][ram_disk]") -{ - GIVEN("A boot modules registry with one valid module") - { - auto storage = std::vector{4096, std::byte{0x0}}; - auto registry = kapi::boot_modules::boot_module_registry{}; - registry.add_boot_module({ - .name = "test_module", - .start_address = kapi::memory::linear_address{storage.data()}, - .size = storage.size(), - }); - - auto controller = kstd::make_shared(®istry); - - WHEN("the controller is initialized") - { - auto succeeded = controller->init(); - - THEN("initialization succeeds") - { - REQUIRE(succeeded); - } - - THEN("the RAM disk is reachable as a child of the controller") - { - REQUIRE(controller->children().size() == 1); - REQUIRE(controller->children()[0]->name() == "ram0"); - } - - THEN("the RAM disk is reachable through the global device tree") - { - REQUIRE(kapi::devices::find_device("ram0")); - } - } - } - - GIVEN("A boot modules registry with one invalid module") - { - auto registry = kapi::boot_modules::boot_module_registry{}; - registry.add_boot_module({ - .name = "invalid module", - .start_address = kapi::memory::linear_address{nullptr}, - .size = 0, - }); - - auto controller = kstd::make_shared(®istry); - - WHEN("the controller is initialized") - { - auto succeeded = controller->init(); - - THEN("initialization fails") - { - REQUIRE_FALSE(succeeded); - } - - THEN("the invalid RAM disk i still attache to the tree") - { - REQUIRE(controller->children().size() == 1); - REQUIRE(controller->children()[0]->name() == "ram0"); - } - - THEN("the invalid RAM disk reachable through the global device tree") - { - REQUIRE(kapi::devices::find_device("ram0")); - } - } - } -} \ No newline at end of file diff --git a/kernel/kernel/devices/storage/ram_disk/device.cpp b/kernel/kernel/devices/storage/ram_disk/device.cpp deleted file mode 100644 index a9de0a2e..00000000 --- a/kernel/kernel/devices/storage/ram_disk/device.cpp +++ /dev/null @@ -1,95 +0,0 @@ -#include - -#include - -#include -#include -#include - -#include -#include -#include -#include - -#include - -using namespace kstd::units_literals; - -namespace kernel::devices::storage::ram_disk -{ - namespace - { - constexpr auto ram_disk_block_size = 512_B; - } // namespace - - device::device(kapi::boot_modules::boot_module const & module, std::size_t device_index) - : kapi::devices::device{kstd::format("ram{}", device_index)} - , 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 -> kstd::result - { - if (buffer == nullptr) - { - kapi::system::panic("[RAM DISK DEVICE] read_block called with null buffer."); - } - - auto const info = block_device_utils::calculate_transfer(*this, block_index); - - if (info.to_transfer > 0_B) - { - auto const src = static_cast(m_boot_module.start_address) + info.offset; - kstd::libc::memcpy(buffer, src, info.to_transfer.value); - } - - if (info.remainder > 0_B) - { - kstd::libc::memset(static_cast(buffer) + info.to_transfer, 0, info.remainder.value); - } - - return info.to_transfer; - } - - auto device::write_block(size_t block_index, void const * buffer) -> kstd::result - { - if (buffer == nullptr) - { - kapi::system::panic("[RAM DISK DEVICE] write_block called with null buffer."); - } - - auto const info = block_device_utils::calculate_transfer(*this, block_index); - - if (info.to_transfer > 0_B) - { - auto const dest = static_cast(m_boot_module.start_address) + info.offset; - kstd::libc::memcpy(dest, buffer, info.to_transfer.value); - } - - return info.to_transfer; - } - - auto device::block_size() const -> kstd::units::bytes - { - return ram_disk_block_size; - } - - auto device::capacity() const noexcept -> kstd::units::bytes - { - return kstd::units::bytes{m_boot_module.size}; - } - - auto device::query_interface(kapi::devices::interface interface) -> void * - { - if (interface == kapi::devices::block_device::id) - { - return static_cast(this); - } - - return kapi::devices::device::query_interface(interface); - } -} // namespace kernel::devices::storage::ram_disk \ No newline at end of file diff --git a/kernel/kernel/devices/storage/ram_disk/device.hpp b/kernel/kernel/devices/storage/ram_disk/device.hpp deleted file mode 100644 index e4f99633..00000000 --- a/kernel/kernel/devices/storage/ram_disk/device.hpp +++ /dev/null @@ -1,60 +0,0 @@ -#ifndef TEACH_OS_KERNEL_DEVICES_STORAGE_RAM_DISK_DEVICE_HPP -#define TEACH_OS_KERNEL_DEVICES_STORAGE_RAM_DISK_DEVICE_HPP - -#include -#include - -#include -#include - -#include - -namespace kernel::devices::storage::ram_disk -{ - /** - * @brief Block device for a boot module. - */ - struct device final : kapi::devices::device, kapi::devices::block_device - { - /** - * @brief Create a RAM disk for the @p module. - * @param module Boot module providing the memory region. - */ - device(kapi::boot_modules::boot_module const & module, std::size_t device_index); - - /** - * @brief Initialize the RAM disk device. - * @return true if module backing memory is valid, false otherwise. - */ - auto init() -> bool override; - - /** - * @brief Read one logical block into @p buffer. - * @param block_index Zero-based block index. - * @param buffer Destination buffer, must not be null. - * @note If the request reaches the module end, only available bytes are copied and the rest of the - * logical block is filled with zeros. - */ - auto read_block(size_t block_index, void * buffer) const -> kstd::result override; - - /** - * @brief Write one logical block from @p buffer. - * @param block_index Zero-based block index. - * @param buffer Source buffer, must not be null. - * @note If the request reaches the module end, only the bytes in the module range are written. - */ - auto write_block(size_t block_index, void const * buffer) -> kstd::result override; - - [[nodiscard]] auto block_size() const -> kstd::units::bytes override; - - [[nodiscard]] auto capacity() const noexcept -> kstd::units::bytes override; - - protected: - auto query_interface(kapi::devices::interface interface) -> void * override; - - private: - kapi::boot_modules::boot_module m_boot_module{}; - }; -} // namespace kernel::devices::storage::ram_disk - -#endif \ No newline at end of file diff --git a/kernel/kernel/devices/storage/ram_disk/device.tests.cpp b/kernel/kernel/devices/storage/ram_disk/device.tests.cpp deleted file mode 100644 index 115afd86..00000000 --- a/kernel/kernel/devices/storage/ram_disk/device.tests.cpp +++ /dev/null @@ -1,117 +0,0 @@ -#include - -#include -#include - -#include -#include -#include - -#include -#include -#include -#include - -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}; - - 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(0x1000)}; - boot_module.size = 512; - - WHEN("constructing the device") - { - kernel::devices::storage::ram_disk::device device{boot_module, 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}; - REQUIRE(device.init()); - - WHEN("reading a full block from the device") - { - auto buffer = std::vector(device.block_size().value); - CHECK(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().value))); - } - } - - WHEN("reading from a block index beyond the module size") - { - auto buffer = std::vector(device.block_size().value); - CHECK(device.read_block(10, buffer.data())); - - THEN("the buffer is filled with zeros") - { - REQUIRE_THAT(buffer, - Catch::Matchers::RangeEquals(std::vector(device.block_size().value, 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(device.block_size().value, std::byte{0x01}); - CHECK(device.write_block(0, buffer.data())); - - THEN("the module data is updated") - { - REQUIRE_THAT(std::views::take(storage, device.block_size().value), Catch::Matchers::RangeEquals(buffer)); - } - } - - WHEN("writing to a block index beyond the module size") - { - auto buffer = std::vector(device.block_size().value, std::byte{0x01}); - CHECK(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/kernel/devices/storage/ram_disk/driver.cpp b/kernel/kernel/devices/storage/ram_disk/driver.cpp new file mode 100644 index 00000000..50313a7a --- /dev/null +++ b/kernel/kernel/devices/storage/ram_disk/driver.cpp @@ -0,0 +1,152 @@ +#include + +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +using namespace kstd::units_literals; + +namespace kernel::devices::storage::ram_disk +{ + + namespace + { + constexpr auto ram_disk_block_size = 512_B; + + struct block_device final : kapi::devices::block_device + { + explicit block_device(kapi::boot_modules::boot_module const & module) + : m_module(module) + {} + + auto read_block(std::size_t block_index, void * buffer) const -> kstd::result override + { + if (!buffer) + { + kapi::system::panic("[RAM DISK] read_block called with null buffer."); + } + + auto info = block_device_utils::calculate_transfer(*this, block_index); + + if (info.to_transfer > 0_B) + { + auto source = static_cast(m_module.start_address) + info.offset; + kstd::libc::memcpy(buffer, source, info.to_transfer.value); + } + + if (info.remainder > 0_B) + { + kstd::libc::memset(static_cast(buffer) + info.to_transfer, 0, info.remainder.value); + } + + return info.to_transfer; + } + + auto write_block(std::size_t block_index, void const * buffer) -> kstd::result override + { + if (buffer == nullptr) + { + kapi::system::panic("[RAM DISK] write_block called with null buffer."); + } + + auto const info = block_device_utils::calculate_transfer(*this, block_index); + + if (info.to_transfer > 0_B) + { + auto const dest = static_cast(m_module.start_address) + info.offset; + kstd::libc::memcpy(dest, buffer, info.to_transfer.value); + } + + return info.to_transfer; + } + + [[nodiscard]] auto block_size() const -> kstd::units::bytes override + { + return ram_disk_block_size; + } + + [[nodiscard]] auto capacity() const -> kstd::units::bytes override + { + return kstd::units::bytes{m_module.size}; + } + + private: + kapi::boot_modules::boot_module m_module; + }; + + } // namespace + + auto driver::probe(kapi::devices::device & device) -> kstd::result + { + auto interface = device.as(); + if (!interface) + { + return kstd::failure(make_error_code(kstd::errc::invalid_argument)); + } + + auto const & module = interface->module(); + if (module.start_address.raw() == 0 || module.size == 0) + { + return kstd::failure(make_error_code(kstd::errc::invalid_argument)); + } + + auto implementation = kstd::make_shared(module); + auto name = kstd::format("ram{}", m_next_disk_index); + + auto published = kapi::devices::publish_interface(device.shared_from_this(), name, + implementation.get()); + if (!published) + { + return published; + } + + device.set_driver_data(implementation); + ++m_next_disk_index; + + return kstd::success(); + } + + auto driver::unbind(kapi::devices::device & device) -> void + { + kapi::devices::interface_registry::get().unpublish(device, kapi::devices::block_device::id); + device.set_driver_data(nullptr); + } + + auto driver::claimed_parameter() const -> std::pair + { + return {"type", "ramdisk"}; + } + + auto driver::claimed_major() const -> std::optional + { + return kernel::filesystem::block_major_numbers::ram_disk; + } + + auto driver::query_interface(kapi::devices::interface interface) -> void * + { + if (interface == kapi::boot_modules::boot_module_driver_identification::id) + { + return static_cast(this); + } + + return kapi::devices::driver::query_interface(interface); + } + +} // namespace kernel::devices::storage::ram_disk \ No newline at end of file diff --git a/kernel/kernel/devices/storage/ram_disk/driver.hpp b/kernel/kernel/devices/storage/ram_disk/driver.hpp new file mode 100644 index 00000000..c665eb14 --- /dev/null +++ b/kernel/kernel/devices/storage/ram_disk/driver.hpp @@ -0,0 +1,39 @@ +#ifndef TEACH_OS_KERNEL_DEVICES_STORAGE_RAM_DISK_DRIVER_HPP +#define TEACH_OS_KERNEL_DEVICES_STORAGE_RAM_DISK_DRIVER_HPP + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +namespace kernel::devices::storage::ram_disk +{ + + struct driver final : kapi::devices::driver, kapi::boot_modules::boot_module_driver_identification + { + [[nodiscard]] auto probe(kapi::devices::device & device) -> kstd::result override; + + auto unbind(kapi::devices::device & device) -> void override; + + [[nodiscard]] auto claimed_parameter() const -> std::pair override; + + [[nodiscard]] auto claimed_major() const -> std::optional override; + + protected: + auto query_interface(kapi::devices::interface interface) -> void * override; + + private: + std::size_t m_next_disk_index{}; + }; + +} // namespace kernel::devices::storage::ram_disk + +#endif \ No newline at end of file -- cgit v1.2.3