diff options
| author | Felix Morgner <felix.morgner@ost.ch> | 2026-07-23 23:55:28 +0200 |
|---|---|---|
| committer | Felix Morgner <felix.morgner@ost.ch> | 2026-07-23 23:55:28 +0200 |
| commit | b334a8494bef50c5b90adc1f101464fc8c4c971a (patch) | |
| tree | 591efae83a93d25e45ab3b32d5d3d2e6c94d702b | |
| parent | 7d78433e6ea80b651f80201b6c5beef799887e7f (diff) | |
| download | kernel-b334a8494bef50c5b90adc1f101464fc8c4c971a.tar.xz kernel-b334a8494bef50c5b90adc1f101464fc8c4c971a.zip | |
kernel: port ram disk to new driver architecture
| -rw-r--r-- | arch/x86_64/support/grub.cfg.in | 6 | ||||
| -rw-r--r-- | cspell.json | 1 | ||||
| -rw-r--r-- | kapi/kapi/boot_module/bus.hpp | 71 | ||||
| -rw-r--r-- | kernel/CMakeLists.txt | 4 | ||||
| -rw-r--r-- | kernel/kapi/boot_module/bus.cpp | 102 | ||||
| -rw-r--r-- | kernel/kernel/devices/storage.cpp | 12 | ||||
| -rw-r--r-- | kernel/kernel/devices/storage/ram_disk/controller.cpp | 38 | ||||
| -rw-r--r-- | kernel/kernel/devices/storage/ram_disk/controller.hpp | 31 | ||||
| -rw-r--r-- | kernel/kernel/devices/storage/ram_disk/controller.tests.cpp | 82 | ||||
| -rw-r--r-- | kernel/kernel/devices/storage/ram_disk/device.cpp | 95 | ||||
| -rw-r--r-- | kernel/kernel/devices/storage/ram_disk/device.hpp | 60 | ||||
| -rw-r--r-- | kernel/kernel/devices/storage/ram_disk/device.tests.cpp | 117 | ||||
| -rw-r--r-- | kernel/kernel/devices/storage/ram_disk/driver.cpp | 152 | ||||
| -rw-r--r-- | kernel/kernel/devices/storage/ram_disk/driver.hpp | 39 | ||||
| -rw-r--r-- | libs/kstd/kstd/cstring.hpp | 1 | ||||
| -rw-r--r-- | libs/kstd/kstd/libc/string.cpp | 15 |
16 files changed, 395 insertions, 431 deletions
diff --git a/arch/x86_64/support/grub.cfg.in b/arch/x86_64/support/grub.cfg.in index 45c33560..06701fdc 100644 --- a/arch/x86_64/support/grub.cfg.in +++ b/arch/x86_64/support/grub.cfg.in @@ -3,8 +3,8 @@ default=0 menuentry "TeachOS" { multiboot2 /$<TARGET_FILE_NAME:kernel> - module2 /modules/ext2_4KB_fs.img - module2 /modules/ext2_1KB_fs.img - module2 /modules/ext2_2KB_fs.img + module2 /modules/ext2_4KB_fs.img type=ramdisk + module2 /modules/ext2_1KB_fs.img type=ramdisk + module2 /modules/ext2_2KB_fs.img type=ramdisk boot }
\ No newline at end of file diff --git a/cspell.json b/cspell.json index 99eea3e0..26d43d10 100644 --- a/cspell.json +++ b/cspell.json @@ -36,6 +36,7 @@ "nullptr", "println", "raii", + "ramdisk", "rdmsr", "RSDP", "rsdt", diff --git a/kapi/kapi/boot_module/bus.hpp b/kapi/kapi/boot_module/bus.hpp new file mode 100644 index 00000000..e569b253 --- /dev/null +++ b/kapi/kapi/boot_module/bus.hpp @@ -0,0 +1,71 @@ +#ifndef TEACHOS_KAPI_BOOT_MODULE_BUS_HPP +#define TEACHOS_KAPI_BOOT_MODULE_BUS_HPP + +#include <kapi/boot_module/boot_module.hpp> +#include <kapi/boot_module/boot_module_registry.hpp> +#include <kapi/devices.hpp> + +#include <kstd/result.hpp> + +#include <cstddef> +#include <string_view> +#include <utility> + +namespace kapi::boot_modules +{ + + struct boot_module_identification + { + constexpr auto static id = devices::interface{"boot_module_identification"}; + + virtual ~boot_module_identification() = default; + + [[nodiscard]] auto virtual command_line() const -> std::string_view = 0; + + [[nodiscard]] auto virtual module() const -> boot_module const & = 0; + }; + + struct boot_module_driver_identification + { + constexpr auto static id = devices::interface{"boot_module_driver_identification"}; + + virtual ~boot_module_driver_identification() = default; + + [[nodiscard]] virtual auto claimed_parameter() const -> std::pair<std::string_view, std::string_view> = 0; + }; + + struct boot_module_device final : kapi::devices::device, boot_module_identification + { + boot_module_device(std::size_t index, boot_module const & module); + + auto init() -> bool override; + + auto command_line() const -> std::string_view override; + + auto module() const -> boot_module const & override; + + protected: + auto query_interface(kapi::devices::interface interface) -> void * override; + + private: + boot_module m_module; + }; + + struct boot_module_bus final : kapi::devices::bus, kapi::devices::bus_protocol + { + explicit boot_module_bus(boot_module_registry const * registry); + + auto enumerate(kapi::devices::bus & self) -> void override; + + [[nodiscard]] auto match(kapi::devices::device const & dev, kapi::devices::driver const & drv) const + -> kstd::result<unsigned> override; + + [[nodiscard]] auto protocol() -> kapi::devices::bus_protocol * override; + + private: + boot_module_registry const * m_registry; + }; + +} // namespace kapi::boot_modules + +#endif
\ No newline at end of file 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 <kapi/boot_module/bus.hpp> + +#include <kapi/boot_modules.hpp> +#include <kapi/devices.hpp> + +#include <kstd/format.hpp> +#include <kstd/memory.hpp> +#include <kstd/result.hpp> +#include <kstd/string.hpp> + +#include <cstddef> +#include <ranges> +#include <string_view> + +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<boot_module_identification *>(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<boot_module_device>(index++, module)); + } + } + + auto boot_module_bus::match(kapi::devices::device const & dev, kapi::devices::driver const & drv) const + -> kstd::result<unsigned> + { + auto const * ident = dev.as<boot_module_identification>(); + auto const * claims = drv.as<boot_module_driver_identification>(); + + 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 <kernel/devices/storage.hpp> -#include <kernel/devices/storage/ram_disk/controller.hpp> +#include <kernel/devices/storage/ram_disk/driver.hpp> +#include <kapi/boot_module/bus.hpp> #include <kapi/boot_modules.hpp> #include <kapi/devices.hpp> +#include <kapi/devices/driver_registry.hpp> #include <kstd/memory.hpp> @@ -11,8 +13,12 @@ namespace kernel::devices::storage { auto init() -> void { - kapi::devices::get_root_bus()->add_child( - kstd::make_shared<ram_disk::controller>(&kapi::boot_modules::get_boot_module_registry())); + kapi::devices::driver_registry::get().add(kstd::make_shared<ram_disk::driver>()); + + auto modules_bus = + kstd::make_shared<kapi::boot_modules::boot_module_bus>(&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<kapi::devices::device> 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 <kernel/devices/storage/ram_disk/controller.hpp> - -#include <kernel/devices/storage/ram_disk/device.hpp> - -#include <kapi/boot_modules.hpp> -#include <kapi/devices.hpp> -#include <kapi/system.hpp> - -#include <algorithm> -#include <cstddef> - -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<ram_disk::device>(module, current_device_index++); - - if (auto published = kapi::devices::publish_interface<kapi::devices::block_device>(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 <kapi/boot_modules.hpp> -#include <kapi/devices.hpp> - -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 <kernel/devices/storage/ram_disk/controller.hpp> - -#include <kapi/boot_modules.hpp> -#include <kapi/devices.hpp> -#include <kapi/memory.hpp> - -#include <kstd/memory.hpp> - -#include <catch2/catch_test_macros.hpp> - -#include <cstddef> -#include <vector> - -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<std::byte>{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<kernel::devices::storage::ram_disk::controller>(®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<kernel::devices::storage::ram_disk::controller>(®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 <kernel/devices/storage/ram_disk/device.hpp> - -#include <kernel/devices/block_device_utils.hpp> - -#include <kapi/boot_module/boot_module.hpp> -#include <kapi/devices.hpp> -#include <kapi/system.hpp> - -#include <kstd/cstring.hpp> -#include <kstd/format.hpp> -#include <kstd/result.hpp> -#include <kstd/units.hpp> - -#include <cstddef> - -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<kstd::units::bytes> - { - 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<std::byte const *>(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<std::byte *>(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<kstd::units::bytes> - { - 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<std::byte *>(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<kapi::devices::block_device *>(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 <kapi/boot_module/boot_module.hpp> -#include <kapi/devices.hpp> - -#include <kstd/result.hpp> -#include <kstd/units.hpp> - -#include <cstddef> - -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<kstd::units::bytes> 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<kstd::units::bytes> 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 <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}; - - 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}; - - 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<std::byte>(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<std::byte>(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<std::byte>(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<std::byte>(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<std::byte>(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 <kernel/devices/storage/ram_disk/driver.hpp> + +#include <kernel/devices/block_device_utils.hpp> +#include <kernel/filesystem/reserved_numbers.hpp> + +#include <kapi/boot_module/bus.hpp> +#include <kapi/boot_modules.hpp> +#include <kapi/devices.hpp> +#include <kapi/system.hpp> + +#include <kstd/cstring.hpp> +#include <kstd/format.hpp> +#include <kstd/memory.hpp> +#include <kstd/result.hpp> +#include <kstd/system_error.hpp> +#include <kstd/units.hpp> + +#include <cstddef> +#include <cstdint> +#include <optional> +#include <string_view> +#include <utility> + +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<kstd::units::bytes> 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<std::byte const *>(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<std::byte *>(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<kstd::units::bytes> 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<std::byte *>(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<void> + { + auto interface = device.as<kapi::boot_modules::boot_module_identification>(); + 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<struct block_device>(module); + auto name = kstd::format("ram{}", m_next_disk_index); + + auto published = kapi::devices::publish_interface<kapi::devices::block_device>(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<std::string_view, std::string_view> + { + return {"type", "ramdisk"}; + } + + auto driver::claimed_major() const -> std::optional<std::uint8_t> + { + 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<kapi::boot_modules::boot_module_driver_identification *>(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 <kapi/boot_module/bus.hpp> +#include <kapi/boot_modules.hpp> +#include <kapi/devices.hpp> + +#include <kstd/result.hpp> +#include <kstd/units.hpp> + +#include <cstddef> +#include <cstdint> +#include <optional> +#include <string_view> +#include <utility> + +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<void> override; + + auto unbind(kapi::devices::device & device) -> void override; + + [[nodiscard]] auto claimed_parameter() const -> std::pair<std::string_view, std::string_view> override; + + [[nodiscard]] auto claimed_major() const -> std::optional<std::uint8_t> 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 diff --git a/libs/kstd/kstd/cstring.hpp b/libs/kstd/kstd/cstring.hpp index bd8b28d8..9678f77f 100644 --- a/libs/kstd/kstd/cstring.hpp +++ b/libs/kstd/kstd/cstring.hpp @@ -12,6 +12,7 @@ namespace kstd::libc auto memset(void * dest, int value, std::size_t size) noexcept -> void *; auto memmove(void * dest, void const * src, std::size_t size) noexcept -> void *; auto memcmp(void const * lhs, void const * rhs, std::size_t size) noexcept -> int; + auto memchr(void const * buffer, int character, std::size_t size) noexcept -> void *; auto strlen(char const * string) noexcept -> std::size_t; } diff --git a/libs/kstd/kstd/libc/string.cpp b/libs/kstd/kstd/libc/string.cpp index 15ecc70f..986f63a6 100644 --- a/libs/kstd/kstd/libc/string.cpp +++ b/libs/kstd/kstd/libc/string.cpp @@ -1,3 +1,5 @@ +#include <kstd/string.hpp> + #include <kstd/cstring.hpp> #include <algorithm> @@ -70,6 +72,19 @@ namespace kstd::libc return dest; } + auto memchr(void const * buffer, int character, std::size_t size) noexcept -> void * + { + auto as_char_ptr = reinterpret_cast<char const *>(buffer); + auto found = kstd::char_traits<char>::find(as_char_ptr, size, static_cast<char>(character)); + + if (found == as_char_ptr + size) + { + return nullptr; + } + + return const_cast<void *>(static_cast<void const *>(found)); + } + auto strlen(char const * string) noexcept -> std::size_t { return std::distance(string, std::ranges::find(string, nullptr, '\0')); |
