diff options
| author | Lukas Oesch <lukas.oesch@ost.ch> | 2026-06-10 10:40:46 +0200 |
|---|---|---|
| committer | Lukas Oesch <lukas.oesch@ost.ch> | 2026-06-10 10:40:46 +0200 |
| commit | 33abd5cf264cb9e34121082105b0bc17b3cf7a36 (patch) | |
| tree | 36b15d53fea04f4f9d9af817100f7ad013bd9b5c /kernel/kapi | |
| parent | d01caf1c4aef3c89c68b9d1cc9fe56445f0860b5 (diff) | |
| parent | 7e27130c342b7299a1d2188a7192a7f17b5ac2ad (diff) | |
| download | kernel-33abd5cf264cb9e34121082105b0bc17b3cf7a36.tar.xz kernel-33abd5cf264cb9e34121082105b0bc17b3cf7a36.zip | |
Merge of BA-FS26 branch into develop
See merge request teachos/kernel!49
Diffstat (limited to 'kernel/kapi')
| -rw-r--r-- | kernel/kapi/acpi.cpp | 40 | ||||
| -rw-r--r-- | kernel/kapi/boot_modules.cpp | 41 | ||||
| -rw-r--r-- | kernel/kapi/cio.cpp | 2 | ||||
| -rw-r--r-- | kernel/kapi/cpu.cpp | 35 | ||||
| -rw-r--r-- | kernel/kapi/cpu.tests.cpp | 19 | ||||
| -rw-r--r-- | kernel/kapi/devices.cpp | 86 | ||||
| -rw-r--r-- | kernel/kapi/devices/bus.cpp | 72 | ||||
| -rw-r--r-- | kernel/kapi/devices/cpu.cpp | 31 | ||||
| -rw-r--r-- | kernel/kapi/devices/device.cpp | 43 | ||||
| -rw-r--r-- | kernel/kapi/filesystem.cpp | 76 | ||||
| -rw-r--r-- | kernel/kapi/filesystem.tests.cpp | 199 | ||||
| -rw-r--r-- | kernel/kapi/interrupts.cpp | 65 | ||||
| -rw-r--r-- | kernel/kapi/memory.cpp | 60 | ||||
| -rw-r--r-- | kernel/kapi/system.cpp | 4 | ||||
| -rw-r--r-- | kernel/kapi/system.tests.cpp | 30 |
15 files changed, 792 insertions, 11 deletions
diff --git a/kernel/kapi/acpi.cpp b/kernel/kapi/acpi.cpp new file mode 100644 index 0000000..b6d5cdf --- /dev/null +++ b/kernel/kapi/acpi.cpp @@ -0,0 +1,40 @@ +#include <kapi/acpi.hpp> + +#include <kernel/acpi/manager.hpp> + +#include <kapi/system.hpp> + +#include <acpi/acpi.hpp> + +#include <kstd/memory> + +#include <atomic> +#include <optional> +#include <string_view> + +namespace kapi::acpi +{ + + namespace + { + auto constinit manager = std::optional<kernel::acpi::manager>{}; + } // namespace + + auto init(::acpi::rsdp const & sdp) -> bool + { + auto static constinit initialized = std::atomic_flag{}; + if (initialized.test_and_set()) + { + system::panic("[OS:ACPI] The ACPI manager has already been initialized!"); + } + + manager.emplace(sdp); + return manager->load_tables(); + } + + auto get_table(std::string_view signature) -> kstd::observer_ptr<::acpi::table_header const> + { + return manager->get_table(signature); + } + +}; // namespace kapi::acpi diff --git a/kernel/kapi/boot_modules.cpp b/kernel/kapi/boot_modules.cpp new file mode 100644 index 0000000..5629b77 --- /dev/null +++ b/kernel/kapi/boot_modules.cpp @@ -0,0 +1,41 @@ +#include <kapi/boot_modules.hpp> + +#include <kapi/system.hpp> + +#include <optional> + +namespace +{ + constinit auto static registry = std::optional<kapi::boot_modules::boot_module_registry>{}; +} // namespace + +namespace kapi::boot_modules +{ + auto set_boot_module_registry(boot_module_registry & new_registry) -> void + { + if (registry) + { + system::panic("[x86_64] Boot module registry has already been set."); + } + + registry = new_registry; + } + + auto get_boot_module_registry() -> boot_module_registry const & + { + if (!registry) + { + system::panic("[x86_64] Boot module registry has not been initialized."); + } + + return *registry; + } +} // namespace kapi::boot_modules + +namespace kernel::tests::boot_modules +{ + auto deinit() -> void + { + registry.reset(); + } +} // namespace kernel::tests::boot_modules diff --git a/kernel/kapi/cio.cpp b/kernel/kapi/cio.cpp index d447a6a..96f043c 100644 --- a/kernel/kapi/cio.cpp +++ b/kernel/kapi/cio.cpp @@ -1,4 +1,4 @@ -#include "kapi/cio.hpp" +#include <kapi/cio.hpp> #include <optional> #include <string_view> diff --git a/kernel/kapi/cpu.cpp b/kernel/kapi/cpu.cpp new file mode 100644 index 0000000..7b1a43b --- /dev/null +++ b/kernel/kapi/cpu.cpp @@ -0,0 +1,35 @@ +#include <kapi/cpu.hpp> + +#include <kapi/system.hpp> + +#include <kstd/print> + +namespace kapi::cpu +{ + + namespace + { + auto handle_page_fault(kapi::cpu::exception const & context) -> bool + { + kstd::println(kstd::print_sink::stderr, "\tFault address: {:#018x}", context.access_address); + kstd::println(kstd::print_sink::stderr, "\tPresent: {}", context.is_present); + kstd::println(kstd::print_sink::stderr, "\tWrite: {}", context.is_write_access); + kstd::println(kstd::print_sink::stderr, "\tUser: {}", context.is_user_mode); + + kapi::system::panic("Halting the system due to an unrecoverable page fault."); + } + } // namespace + + auto dispatch(exception const & context) -> bool + { + kstd::println(kstd::print_sink::stderr, "[OS:CPU] {} @ {:#018x}", context.type, context.instruction_pointer); + switch (context.type) + { + case kapi::cpu::exception::type::page_fault: + return handle_page_fault(context); + default: + return false; + } + } + +} // namespace kapi::cpu
\ No newline at end of file diff --git a/kernel/kapi/cpu.tests.cpp b/kernel/kapi/cpu.tests.cpp new file mode 100644 index 0000000..9ce2917 --- /dev/null +++ b/kernel/kapi/cpu.tests.cpp @@ -0,0 +1,19 @@ +#include <kapi/cpu.hpp> + +#include <kernel/test_support/cpu.hpp> + +#include <catch2/catch_test_macros.hpp> + +SCENARIO("Kernel testing kapi::cpu shims", "[support]") +{ + GIVEN("the test support infrastructure is initialized") + { + WHEN("a CPU halt is requested") + { + THEN("the correct exception is thrown") + { + REQUIRE_THROWS_AS(kapi::cpu::halt(), kernel::tests::cpu::halt); + } + } + } +}
\ No newline at end of file diff --git a/kernel/kapi/devices.cpp b/kernel/kapi/devices.cpp new file mode 100644 index 0000000..572227e --- /dev/null +++ b/kernel/kapi/devices.cpp @@ -0,0 +1,86 @@ +#include <kapi/devices.hpp> + +#include <kernel/devices/root_bus.hpp> + +#include <kapi/system.hpp> + +#include <kstd/flat_map> +#include <kstd/memory> +#include <kstd/print> + +#include <atomic> +#include <cstddef> +#include <optional> +#include <string_view> +#include <utility> + +namespace kapi::devices +{ + namespace + { + auto constinit next_major_number = std::atomic_size_t{1}; + auto constinit root_bus = std::optional<kernel::devices::root_bus>{}; + auto constinit device_tree = kstd::flat_map<std::pair<std::size_t, std::size_t>, kstd::observer_ptr<device>>{}; + } // namespace + + auto init() -> void + { + auto static is_initialized = std::atomic_flag{}; + if (is_initialized.test_and_set()) + { + return; + } + + auto & bus = root_bus.emplace(); + register_device(bus); + bus.init(); + } + + auto get_root_bus() -> bus & + { + if (!root_bus.has_value()) + { + kapi::system::panic("[OS:DEV] Root bus not initialized!"); + } + return *root_bus; + } + + auto allocate_major_number() -> std::size_t + { + return next_major_number++; + } + + auto register_device(device & device) -> bool + { + kstd::println("[OS:DEV] Registering device {}@{}:{}", device.name(), device.major(), device.minor()); + return device_tree.emplace(std::pair{device.major(), device.minor()}, &device).second; + } + + auto unregister_device(device &) -> bool + { + kstd::println("[OS:DEV] TODO: implement device deregistration"); + return false; + } + + auto find_device(std::size_t major, std::size_t minor) -> kstd::observer_ptr<device> + { + if (device_tree.contains(std::pair{major, minor})) + { + return device_tree.at(std::pair{major, minor}); + } + return nullptr; + } + + auto find_device(std::string_view name) -> kstd::observer_ptr<device> + { + for (auto const & [key, value] : device_tree) + { + if (value->name() == name) + { + return value; + } + } + return nullptr; + } + +} // namespace kapi::devices
\ No newline at end of file diff --git a/kernel/kapi/devices/bus.cpp b/kernel/kapi/devices/bus.cpp new file mode 100644 index 0000000..59753f7 --- /dev/null +++ b/kernel/kapi/devices/bus.cpp @@ -0,0 +1,72 @@ +#include <kapi/devices/bus.hpp> + +#include <kapi/devices.hpp> +#include <kapi/system.hpp> + +#include <kstd/memory> +#include <kstd/print> +#include <kstd/string> +#include <kstd/vector> + +#include <algorithm> +#include <cstddef> +#include <utility> + +namespace kapi::devices +{ + bus::bus(std::size_t major, std::size_t minor, kstd::string const & name) + : device(major, minor, name) + {} + + auto bus::init() -> bool + { + if (m_init_was_called.test_and_set()) + { + kstd::println(kstd::print_sink::stderr, "[OS:DEV] Bus {}:{}:{} already initialized", name(), major(), minor()); + return true; + } + + if (!probe()) + { + kstd::println(kstd::print_sink::stderr, "[OS:DEV] Bus {}:{}:{} probe failed", name(), major(), minor()); + return false; + } + + auto child_status = std::ranges::fold_left(m_devices, true, [&](bool acc, auto & child) -> bool { + kstd::println("[OS:DEV] Initializing child device {}@{}", child->name(), name()); + return child->init() && acc; + }); + + m_initialized.test_and_set(); + + return child_status; + } + + auto bus::add_child(kstd::unique_ptr<device> child) -> void + { + auto observer = m_observers.emplace_back(child.get()); + child->set_parent(kstd::make_observer(this)); + m_devices.push_back(std::move(child)); + kapi::devices::register_device(*observer); + + if (m_initialized.test()) + { + kstd::println("[OS:DEV] Initializing child device {}@{}", observer->name(), name()); + if (!observer->init()) + { + kapi::system::panic("[OS:DEV] Failed to initialize child device"); + } + } + } + + [[nodiscard]] auto bus::children() const -> kstd::vector<kstd::observer_ptr<device>> const & + { + return m_observers; + } + + auto bus::probe() -> bool + { + return true; + } + +} // namespace kapi::devices
\ No newline at end of file diff --git a/kernel/kapi/devices/cpu.cpp b/kernel/kapi/devices/cpu.cpp new file mode 100644 index 0000000..f0e1d72 --- /dev/null +++ b/kernel/kapi/devices/cpu.cpp @@ -0,0 +1,31 @@ +#include <kapi/devices/cpu.hpp> + +#include <kapi/devices.hpp> + +#include <cstddef> +#include <cstdint> + +namespace kapi::devices +{ + + cpu::core::core(std::size_t major_number, std::size_t minor_number, std::uint64_t hardware_id, bool is_bsp) + : kapi::devices::bus{major_number, minor_number, "cpu_core"} + , m_hardware_id{hardware_id} + , m_is_bsp{is_bsp} + {} + + auto cpu::core::hardware_id() const -> std::uint64_t + { + return m_hardware_id; + } + + auto cpu::core::is_bsp() const -> bool + { + return m_is_bsp; + } + + cpu::cpu(std::size_t major, std::size_t minor) + : kapi::devices::bus{major, minor, "cpu"} + {} + +} // namespace kapi::devices
\ No newline at end of file diff --git a/kernel/kapi/devices/device.cpp b/kernel/kapi/devices/device.cpp new file mode 100644 index 0000000..8b5d6b9 --- /dev/null +++ b/kernel/kapi/devices/device.cpp @@ -0,0 +1,43 @@ +#include <kapi/devices/device.hpp> + +#include <kapi/devices/bus.hpp> + +#include <kstd/memory> +#include <kstd/string> + +#include <cstddef> + +namespace kapi::devices +{ + device::device(size_t major, size_t minor, kstd::string const & name) + : m_major(major) + , m_minor(minor) + , m_name(name) + {} + + [[nodiscard]] auto device::major() const -> size_t + { + return m_major; + } + + [[nodiscard]] auto device::minor() const -> size_t + { + return m_minor; + } + + [[nodiscard]] auto device::name() const -> kstd::string const & + { + return m_name; + } + + [[nodiscard]] auto device::is_block_device() const -> bool + { + return false; + } + + auto device::set_parent(kstd::observer_ptr<bus> parent) -> void + { + m_parent = parent; + } + +} // namespace kapi::devices
\ No newline at end of file diff --git a/kernel/kapi/filesystem.cpp b/kernel/kapi/filesystem.cpp new file mode 100644 index 0000000..68b51c9 --- /dev/null +++ b/kernel/kapi/filesystem.cpp @@ -0,0 +1,76 @@ +#include <kapi/filesystem.hpp> + +#include <kernel/filesystem/open_file_descriptor.hpp> +#include <kernel/filesystem/open_file_table.hpp> +#include <kernel/filesystem/vfs.hpp> + +#include <kstd/memory> +#include <kstd/unikstd.h> + +#include <cstddef> +#include <string_view> + +namespace kapi::filesystem +{ + auto mount(std::string_view source, std::string_view target) -> kstd::ssize_t + { + if (kernel::filesystem::vfs::get().do_mount(source, target) == kernel::filesystem::vfs::operation_result::success) + { + return 0; + } + return -1; + } + + auto umount(std::string_view target) -> kstd::ssize_t + { + if (kernel::filesystem::vfs::get().unmount(target) == kernel::filesystem::vfs::operation_result::success) + { + return 0; + } + return -1; + } + + auto open(std::string_view path) -> kstd::ssize_t + { + if (auto dentry = kernel::filesystem::vfs::get().open(path)) + { + auto open_file_descriptor = kstd::make_shared<kernel::filesystem::open_file_descriptor>(dentry); + return kernel::filesystem::open_file_table::get().add_file(open_file_descriptor); + } + + return -1; + } + + auto close(size_t file_descriptor) -> kstd::ssize_t + { + if (auto open_file_descriptor = kernel::filesystem::open_file_table::get().file(file_descriptor)) + { + if (kernel::filesystem::vfs::get().close(open_file_descriptor->get_dentry()->absolute_path()) == + kernel::filesystem::vfs::operation_result::success) + { + return kernel::filesystem::open_file_table::get().remove_file(file_descriptor); + } + } + return -1; + } + + auto read(size_t file_descriptor, void * buffer, size_t size) -> kstd::ssize_t + { + if (auto open_file_descriptor = kernel::filesystem::open_file_table::get().file(file_descriptor)) + { + return open_file_descriptor->read(buffer, size); + } + + return -1; + } + + auto write(size_t file_descriptor, void const * buffer, size_t size) -> kstd::ssize_t + { + if (auto open_file_descriptor = kernel::filesystem::open_file_table::get().file(file_descriptor)) + { + return open_file_descriptor->write(buffer, size); + } + + return -1; + } +} // namespace kapi::filesystem
\ No newline at end of file diff --git a/kernel/kapi/filesystem.tests.cpp b/kernel/kapi/filesystem.tests.cpp new file mode 100644 index 0000000..d241afa --- /dev/null +++ b/kernel/kapi/filesystem.tests.cpp @@ -0,0 +1,199 @@ +#include <kapi/filesystem.hpp> + +#include <kernel/test_support/filesystem/storage_boot_module_vfs_fixture.hpp> + +#include <catch2/catch_test_macros.hpp> + +#include <algorithm> +#include <cstddef> +#include <filesystem> +#include <string_view> +#include <vector> + +SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_vfs_fixture, "Kapi filesystem with real images", + "[kapi][filesystem]") +{ + 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"; + + GIVEN("Two real image files") + { + 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})); + + THEN("files can be opened, read and closed again") + { + auto fd = kapi::filesystem::open("/information/info_1.txt"); + REQUIRE(fd >= 0); + + auto buffer = std::vector<std::byte>(6); + auto bytes_read = kapi::filesystem::read(fd, buffer.data(), buffer.size()); + REQUIRE(bytes_read >= 0); + + std::string_view buffer_as_str{reinterpret_cast<char *>(buffer.data()), static_cast<size_t>(bytes_read)}; + REQUIRE(buffer_as_str == "info_1"); + + REQUIRE(kapi::filesystem::close(fd) == 0); + } + + THEN("files can be opened through absolute symbolic link, read and closed again") + { + auto fd = kapi::filesystem::open("/symlinks/information_directory_absolute/info_1.txt"); + REQUIRE(fd >= 0); + + auto buffer = std::vector<std::byte>(6); + auto bytes_read = kapi::filesystem::read(fd, buffer.data(), buffer.size()); + REQUIRE(bytes_read >= 0); + + std::string_view buffer_as_str{reinterpret_cast<char *>(buffer.data()), static_cast<size_t>(bytes_read)}; + REQUIRE(buffer_as_str == "info_1"); + + REQUIRE(kapi::filesystem::close(fd) == 0); + } + + THEN("files can be opened through relative symbolic link, read and closed again") + { + auto fd = kapi::filesystem::open("/symlinks/information_directory_relative/info_1.txt"); + REQUIRE(fd >= 0); + + auto buffer = std::vector<std::byte>(6); + auto bytes_read = kapi::filesystem::read(fd, buffer.data(), buffer.size()); + REQUIRE(bytes_read >= 0); + + std::string_view buffer_as_str{reinterpret_cast<char *>(buffer.data()), static_cast<size_t>(bytes_read)}; + REQUIRE(buffer_as_str == "info_1"); + + REQUIRE(kapi::filesystem::close(fd) == 0); + } + + THEN("files can be opened through relative symbolic link over multiple mount points, read and closed again") + { + kapi::filesystem::mount("/archiv/2024.img", "/information"); + + auto fd = kapi::filesystem::open("/information/symlinks/traverse_back_twice/information/sheep_1.txt"); + REQUIRE(fd >= 0); + + auto buffer = std::vector<std::byte>(7); + auto bytes_read = kapi::filesystem::read(fd, buffer.data(), buffer.size()); + REQUIRE(bytes_read >= 0); + + std::string_view buffer_as_str{reinterpret_cast<char *>(buffer.data()), static_cast<size_t>(bytes_read)}; + REQUIRE(buffer_as_str == "sheep_1"); + + REQUIRE(kapi::filesystem::close(fd) == 0); + } + + THEN("a filesystem can be mounted, files can be opened, read and closed again and unmounted") + { + REQUIRE(kapi::filesystem::mount("/dev/ram16", "/information") == 0); + + auto fd = kapi::filesystem::open("/information/monkey_house/monkey_1.txt"); + REQUIRE(fd >= 0); + + auto buffer = std::vector<std::byte>(8); + auto bytes_read = kapi::filesystem::read(fd, buffer.data(), buffer.size()); + REQUIRE(bytes_read >= 0); + + std::string_view buffer_as_str{reinterpret_cast<char *>(buffer.data()), static_cast<size_t>(bytes_read)}; + REQUIRE(buffer_as_str == "monkey_1"); + + REQUIRE(kapi::filesystem::close(fd) == 0); + REQUIRE(kapi::filesystem::umount("/information") == 0); + } + + THEN("a filesystem cannot be unmounted if files are still open and can be unmounted after files are closed") + { + REQUIRE(kapi::filesystem::mount("/dev/ram16", "/information") == 0); + + auto fd = kapi::filesystem::open("/information/monkey_house/monkey_1.txt"); + REQUIRE(fd >= 0); + + REQUIRE(kapi::filesystem::umount("/information") < 0); + + REQUIRE(kapi::filesystem::close(fd) == 0); + REQUIRE(kapi::filesystem::umount("/information") == 0); + } + + THEN("device can be opened as file and read from") + { + auto fd = kapi::filesystem::open("/dev/ram0"); + REQUIRE(fd >= 0); + + auto buffer = std::vector<std::byte>(512); + auto bytes_read = kapi::filesystem::read(fd, buffer.data(), buffer.size()); + REQUIRE(bytes_read >= 0); + + REQUIRE(kapi::filesystem::close(fd) == 0); + } + + THEN("device can be opened as file and written to and read from again") + { + auto read_fd = kapi::filesystem::open("/dev/ram16"); + REQUIRE(read_fd >= 0); + + auto buffer = std::vector<std::byte>(512, std::byte{0xAB}); + auto bytes_written = kapi::filesystem::write(read_fd, buffer.data(), buffer.size()); + REQUIRE(bytes_written >= 0); + + auto write_fd = kapi::filesystem::open("/dev/ram16"); + REQUIRE(write_fd >= 0); + + auto read_buffer = std::vector<std::byte>(512); + auto bytes_read = kapi::filesystem::read(write_fd, read_buffer.data(), read_buffer.size()); + REQUIRE(bytes_read >= 0); + + REQUIRE(std::equal(buffer.begin(), buffer.end(), read_buffer.begin())); + + REQUIRE(kapi::filesystem::close(write_fd) == 0); + REQUIRE(kapi::filesystem::close(read_fd) == 0); + } + + THEN("invalid paths cannot be mounted or unmounted") + { + REQUIRE(kapi::filesystem::mount("/dev/ram16", "invalid_path") < 0); + } + + THEN("invalid paths cannot be unmounted") + { + REQUIRE(kapi::filesystem::umount("invalid_path") < 0); + } + + THEN("non existent files cannot be opened") + { + auto fd = kapi::filesystem::open("/information/non_existent.txt"); + REQUIRE(fd < 0); + } + + THEN("not opened files cannot closed") + { + REQUIRE(kapi::filesystem::close(999) < 0); + } + + THEN("same file cannot be closed twice") + { + auto fd = kapi::filesystem::open("/information/info_1.txt"); + REQUIRE(fd >= 0); + + REQUIRE(kapi::filesystem::close(fd) == 0); + REQUIRE(kapi::filesystem::close(fd) < 0); + } + + THEN("not opened files cannot be read from") + { + std::vector<std::byte> buffer(10); + auto const invalid_fd = 999uz; + auto bytes_read = kapi::filesystem::read(invalid_fd, buffer.data(), buffer.size()); + REQUIRE(bytes_read < 0); + } + + THEN("not opened files cannot be written to") + { + std::vector<std::byte> buffer(10); + auto const invalid_fd = 999uz; + auto bytes_written = kapi::filesystem::write(invalid_fd, buffer.data(), buffer.size()); + REQUIRE(bytes_written < 0); + } + } +} diff --git a/kernel/kapi/interrupts.cpp b/kernel/kapi/interrupts.cpp new file mode 100644 index 0000000..4efcaa3 --- /dev/null +++ b/kernel/kapi/interrupts.cpp @@ -0,0 +1,65 @@ +#include <kapi/interrupts.hpp> + +#include <kstd/flat_map> +#include <kstd/print> +#include <kstd/vector> + +#include <algorithm> +#include <cstdint> + +namespace kapi::interrupts +{ + + namespace + { + auto constinit handlers = kstd::flat_map<std::uint32_t, kstd::vector<handler *>>{}; + } // namespace + + auto register_handler(std::uint32_t irq_number, handler & handler) -> void + { + if (handlers.contains(irq_number)) + { + auto & handler_list = handlers.at(irq_number); + handler_list.push_back(&handler); + } + else + { + handlers.emplace(irq_number, kstd::vector{&handler}); + } + } + + auto unregister_handler(std::uint32_t irq_number, handler & handler) -> void + { + auto & handler_list = handlers.at(irq_number); + auto [first, last] = std::ranges::remove(handler_list, &handler); + handler_list.erase(first, last); + } + + auto dispatch(std::uint32_t irq_number) -> status + { + if (!handlers.contains(irq_number)) + { + kstd::println(kstd::print_sink::stderr, "[OS:interrupts] No handler for IRQ{}", irq_number); + return status::unhandled; + } + + auto & handler_list = handlers.at(irq_number); + + if (handler_list.empty()) + { + kstd::println(kstd::print_sink::stderr, "[OS:interrupts] No handler for IRQ{}", irq_number); + return status::unhandled; + } + + for (auto handler : handler_list) + { + if (handler && handler->handle_interrupt(irq_number) == status::handled) + { + return status::handled; + } + } + + return status::unhandled; + } + +} // namespace kapi::interrupts
\ No newline at end of file diff --git a/kernel/kapi/memory.cpp b/kernel/kapi/memory.cpp index d8065d4..5ea08b1 100644 --- a/kernel/kapi/memory.cpp +++ b/kernel/kapi/memory.cpp @@ -1,10 +1,12 @@ -#include "kapi/memory.hpp" +#include <kapi/memory.hpp> -#include "kapi/system.hpp" +#include <kernel/memory/bitmap_allocator.hpp> +#include <kernel/memory/mmio_allocator.hpp> -#include "kernel/memory/bitmap_allocator.hpp" +#include <kapi/system.hpp> #include <kstd/print> +#include <kstd/units> #include <algorithm> #include <cstddef> @@ -62,6 +64,7 @@ namespace kapi::memory constinit bad_frame_allocator bad_frame_allocator::instance{}; constinit bad_page_mapper bad_page_mapper::instance{}; auto constinit allocator = std::optional<kernel::memory::bitmap_frame_allocator>{}; + auto constinit mmio_allocator = std::optional<kernel::memory::mmio_allocator>{}; } // namespace constinit auto static active_frame_allocator = static_cast<frame_allocator *>(&bad_frame_allocator::instance); @@ -112,8 +115,10 @@ namespace kapi::memory auto init_pmm(std::size_t frame_count, void (&handoff_handler)(frame_allocator &)) -> void { - auto const bitmap_bytes = (frame_count + 7uz) / 8uz; - auto const bitmap_pages = (bitmap_bytes + page::size - 1uz) / page::size; + using namespace kstd::units_literals; + + auto const bitmap_bytes = kstd::units::bytes{(frame_count + 7uz) / 8uz}; + auto const bitmap_pages = (bitmap_bytes + page::size - 1_B) / page::size; auto const bitmap_frames = allocate_many_frames(bitmap_pages); if (!bitmap_frames) @@ -122,15 +127,20 @@ namespace kapi::memory } auto const flags = page_mapper::flags::writable | page_mapper::flags::supervisor_only | page_mapper::flags::global; + auto bitmap_ptr = static_cast<std::uint64_t *>(nullptr); std::ranges::for_each(std::views::iota(0uz, bitmap_pages), [&](auto index) { auto page = page::containing(pmm_metadata_base + index * page::size); auto frame = memory::frame(bitmap_frames->first.number() + index); - active_page_mapper->map(page, frame, flags); + auto mapped = active_page_mapper->map(page, frame, flags); + if (!bitmap_ptr) + { + bitmap_ptr = reinterpret_cast<std::uint64_t *>(mapped); + } }); - auto bitmap_ptr = static_cast<std::uint64_t *>(pmm_metadata_base); - auto bitmap = std::span{bitmap_ptr, (bitmap_bytes + sizeof(std::uint64_t) - 1uz) / sizeof(std::uint64_t)}; + auto bitmap = + std::span{bitmap_ptr, (bitmap_bytes + kstd::type_size<std::uint64_t> - 1_B) / kstd::type_size<std::uint64_t>}; allocator.emplace(bitmap, frame_count); @@ -139,4 +149,38 @@ namespace kapi::memory kstd::println("[OS:MEM] Physical memory manager initialized."); } + auto init_mmio(linear_address base, std::size_t page_count) -> void + { + mmio_allocator.emplace(base, page_count); + } + + auto allocate_mmio_region(std::size_t page_count) -> mmio_region + { + auto region = mmio_allocator->allocate(page_count); + return {region, page_count}; + } + + auto map_mmio_region(mmio_region region, physical_address hw_base, page_mapper::flags flags) -> std::byte * + { + auto start_page = page::containing(region.first); + auto start_frame = frame::containing(hw_base); + + flags |= page_mapper::flags::uncached; + + auto start = map(start_page, start_frame, flags); + + std::ranges::for_each(std::views::iota(1uz, region.second), [&](auto index) { + auto page = page::containing(region.first + index * page::size); + auto frame = frame::containing(hw_base + index * page::size); + map(page, frame, flags); + }); + + return start; + } + + auto release_mmio_region(mmio_region region) -> void + { + mmio_allocator->release(region.first); + } + } // namespace kapi::memory diff --git a/kernel/kapi/system.cpp b/kernel/kapi/system.cpp index a17d9b9..9819ceb 100644 --- a/kernel/kapi/system.cpp +++ b/kernel/kapi/system.cpp @@ -1,6 +1,6 @@ -#include "kapi/system.hpp" +#include <kapi/system.hpp> -#include "kapi/cpu.hpp" +#include <kapi/cpu.hpp> #include <kstd/print> diff --git a/kernel/kapi/system.tests.cpp b/kernel/kapi/system.tests.cpp new file mode 100644 index 0000000..1e30031 --- /dev/null +++ b/kernel/kapi/system.tests.cpp @@ -0,0 +1,30 @@ +#include <kapi/system.hpp> + +#include <kernel/test_support/cio.hpp> +#include <kernel/test_support/cpu.hpp> + +#include <kstd/print> + +#include <catch2/catch_test_macros.hpp> + +SCENARIO("Kernel testing kapi::system shims", "[support]") +{ + GIVEN("the test support infrastructure is initialized") + { + WHEN("a the system panics") + { + kernel::tests::cio::log_buffer().clear(); + + THEN("the correct exception is thrown") + { + REQUIRE_THROWS_AS(kapi::system::panic("[kernel:tests] Test Panic"), kernel::tests::cpu::halt); + } + + THEN("the message is appended to the log buffer") + { + CHECK_THROWS(kapi::system::panic("[kernel:tests] Test Panic")); + REQUIRE(kernel::tests::cio::log_buffer().flat_messages().contains("[kernel:tests] Test Panic")); + } + } + } +}
\ No newline at end of file |
