From 7d673b1091ee4099086302c87c9bac8f0c41305d Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Fri, 24 Jul 2026 16:28:05 +0200 Subject: x86_64: split files for devices and drivers --- arch/x86_64/CMakeLists.txt | 6 +- arch/x86_64/arch/bus/isa.hpp | 4 ++ arch/x86_64/arch/devices/init.cpp | 11 +-- arch/x86_64/arch/devices/legacy_pit.cpp | 120 -------------------------------- arch/x86_64/arch/devices/legacy_pit.hpp | 64 ----------------- arch/x86_64/arch/devices/pit.cpp | 31 +++++++++ arch/x86_64/arch/devices/pit.hpp | 32 +++++++++ arch/x86_64/arch/drivers/init.cpp | 27 +++++++ arch/x86_64/arch/drivers/init.hpp | 11 +++ arch/x86_64/arch/drivers/pit.cpp | 100 ++++++++++++++++++++++++++ arch/x86_64/arch/drivers/pit.hpp | 47 +++++++++++++ arch/x86_64/kapi/devices.cpp | 6 ++ 12 files changed, 266 insertions(+), 193 deletions(-) delete mode 100644 arch/x86_64/arch/devices/legacy_pit.cpp delete mode 100644 arch/x86_64/arch/devices/legacy_pit.hpp create mode 100644 arch/x86_64/arch/devices/pit.cpp create mode 100644 arch/x86_64/arch/devices/pit.hpp create mode 100644 arch/x86_64/arch/drivers/init.cpp create mode 100644 arch/x86_64/arch/drivers/init.hpp create mode 100644 arch/x86_64/arch/drivers/pit.cpp create mode 100644 arch/x86_64/arch/drivers/pit.hpp (limited to 'arch/x86_64') diff --git a/arch/x86_64/CMakeLists.txt b/arch/x86_64/CMakeLists.txt index 20a48f93..4e4fc52a 100644 --- a/arch/x86_64/CMakeLists.txt +++ b/arch/x86_64/CMakeLists.txt @@ -44,9 +44,13 @@ target_sources("x86_64" PRIVATE # Devices "arch/devices/init.cpp" - "arch/devices/legacy_pit.cpp" + "arch/devices/pit.cpp" "arch/devices/local_apic.cpp" + # Drivers + "arch/drivers/init.cpp" + "arch/drivers/pit.cpp" + # Memory management "arch/memory/kernel_mapper.cpp" "arch/memory/higher_half_mapper.cpp" diff --git a/arch/x86_64/arch/bus/isa.hpp b/arch/x86_64/arch/bus/isa.hpp index a09127dd..aa6eb01a 100644 --- a/arch/x86_64/arch/bus/isa.hpp +++ b/arch/x86_64/arch/bus/isa.hpp @@ -12,12 +12,16 @@ namespace arch::bus { + //! The identification interface used to identify ISA devices. struct isa_identification { + //! The ID of this interface. constexpr auto static id = kapi::devices::interface{"isa_identification"}; + //! Allow for correct destruction through base pointers. virtual ~isa_identification() = default; + //! Return the ISA name of the device. [[nodiscard]] virtual auto isa_name() const -> std::string_view = 0; }; diff --git a/arch/x86_64/arch/devices/init.cpp b/arch/x86_64/arch/devices/init.cpp index f6adcbcf..10848508 100644 --- a/arch/x86_64/arch/devices/init.cpp +++ b/arch/x86_64/arch/devices/init.cpp @@ -2,7 +2,7 @@ #include #include -#include +#include #include #include @@ -14,14 +14,11 @@ #include #include -#include - namespace arch::devices { namespace { - constexpr auto pit_frequency_in_hz = std::uint32_t{100u}; auto get_acpi_root_pointer() -> kstd::observer_ptr<::acpi::rsdp const> { @@ -62,13 +59,11 @@ namespace arch::devices { kstd::println("[x86_64:DEV] Initializing ISA bus..."); - auto isa_bus = kstd::make_shared(); auto root_bus = kapi::devices::get_root_bus(); - + auto isa_bus = kstd::make_shared(); root_bus->add_child(isa_bus); - kapi::devices::driver_registry::get().add(kstd::make_shared(pit_frequency_in_hz)); - isa_bus->add_child(kstd::make_shared()); + isa_bus->add_child(kstd::make_shared()); } } // namespace arch::devices diff --git a/arch/x86_64/arch/devices/legacy_pit.cpp b/arch/x86_64/arch/devices/legacy_pit.cpp deleted file mode 100644 index b24f87ea..00000000 --- a/arch/x86_64/arch/devices/legacy_pit.cpp +++ /dev/null @@ -1,120 +0,0 @@ -#include - -#include -#include - -#include -#include -#include - -#include -#include - -#include -#include -#include -#include - -namespace arch::devices -{ - - using namespace std::string_view_literals; - - namespace - { - using command_port = io::port<0x43, std::uint8_t, io::port_write>; - using channel_0_port = io::port<0x40, std::uint8_t, io::port_write>; - using channel_1_port = io::port<0x41, std::uint8_t, io::port_write>; - using channel_2_port = io::port<0x42, std::uint8_t, io::port_write>; - - constexpr auto base_frequency = 1'193'182u; - constexpr auto square_wave_mode = 0x36; - - constexpr auto pit_names = std::array{"pit"sv}; - } // namespace - - pit_device::pit_device() - : device{"legacy_pit"} - {} - - auto pit_device::isa_name() const -> std::string_view - { - return "pit"; - } - - auto pit_device::query_interface(kapi::devices::interface interface) -> void * - { - if (interface == arch::bus::isa_identification::id) - { - return static_cast(this); - } - - return kapi::devices::device::query_interface(interface); - } - - pit_driver::pit_driver(std::uint32_t frequency_in_hz) - : m_frequency_in_hz{frequency_in_hz} - {} - - auto pit_driver::probe(kapi::devices::device & device) -> kstd::result - { - auto data = kstd::make_shared(0, m_frequency_in_hz, 0); - device.set_driver_data(data); - - auto divisor = static_cast(base_frequency / data->frequency_in_hz); - - kapi::interrupts::register_handler(data->irq_number, *this, data); - - command_port::write(square_wave_mode); - io::wait(); - channel_0_port::write(divisor & 0xff); - io::wait(); - channel_0_port::write(divisor >> 8 & 0xff); - io::wait(); - - return kstd::success(); - } - - auto pit_driver::unbind(kapi::devices::device & device) -> void - { - auto data = static_pointer_cast(device.driver_data()); - - kapi::interrupts::unregister_handler(data->irq_number, *this); - - device.set_driver_data(nullptr); - } - - auto pit_driver::supported_names() const -> std::span - { - return pit_names; - } - - auto pit_driver::handle_interrupt(std::uint32_t irq_number, kstd::weak_ptr context) -> kapi::interrupts::status - { - auto data = static_pointer_cast(context.lock()); - if (!data) - { - return kapi::interrupts::status::unhandled; - } - - if (irq_number != data->irq_number) - { - return kapi::interrupts::status::unhandled; - } - - ++data->ticks; - - return kapi::interrupts::status::handled; - } - - auto pit_driver::query_interface(kapi::devices::interface interface) -> void * - { - if (interface == arch::bus::isa_driver_identification::id) - { - return static_cast(this); - } - - return kapi::devices::driver::query_interface(interface); - } - -} // namespace arch::devices \ No newline at end of file diff --git a/arch/x86_64/arch/devices/legacy_pit.hpp b/arch/x86_64/arch/devices/legacy_pit.hpp deleted file mode 100644 index 31c02207..00000000 --- a/arch/x86_64/arch/devices/legacy_pit.hpp +++ /dev/null @@ -1,64 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_DEVICES_LEGACY_PIT_HPP -#define TEACHOS_ARCH_X86_64_DEVICES_LEGACY_PIT_HPP - -#include - -#include -#include - -#include -#include - -#include -#include -#include - -namespace arch::devices -{ - - //! The ISA device for the legacy Programmable Interrupt Timer. - //! - //! This type identifies the PIT device node to the driver, so the driver can be matched successfully. - struct pit_device final : kapi::devices::device, arch::bus::isa_identification - { - pit_device(); - - //! Get the synthetic ISA identifier for this device. - //! - //! @return the string "pit" - [[nodiscard]] auto isa_name() const -> std::string_view override; - - protected: - auto query_interface(kapi::devices::interface interface) -> void * override; - }; - - //! The driver for the legacy, ISA-connected Programmable Interrupt Timer. - struct pit_driver final : kapi::devices::driver, arch::bus::isa_driver_identification, kapi::interrupts::handler - { - explicit pit_driver(std::uint32_t frequency_in_hz); - - [[nodiscard]] auto probe(kapi::devices::device & device) -> kstd::result override; - - auto unbind(kapi::devices::device & device) -> void override; - - [[nodiscard]] auto supported_names() const -> std::span override; - - auto handle_interrupt(std::uint32_t irq_number, kstd::weak_ptr context) -> kapi::interrupts::status override; - - protected: - auto query_interface(kapi::devices::interface interface) -> void * override; - - private: - struct driver_data - { - std::uint32_t irq_number{}; - std::uint32_t frequency_in_hz{}; - std::uint64_t ticks{}; - }; - - std::uint32_t m_frequency_in_hz{}; - }; - -} // namespace arch::devices - -#endif \ No newline at end of file diff --git a/arch/x86_64/arch/devices/pit.cpp b/arch/x86_64/arch/devices/pit.cpp new file mode 100644 index 00000000..df28288f --- /dev/null +++ b/arch/x86_64/arch/devices/pit.cpp @@ -0,0 +1,31 @@ +#include + +#include + +#include + +#include + +namespace arch::devices +{ + + pit::pit() + : device{"legacy_pit"} + {} + + auto pit::isa_name() const -> std::string_view + { + return "pit"; + } + + auto pit::query_interface(kapi::devices::interface interface) -> void * + { + if (interface == arch::bus::isa_identification::id) + { + return static_cast(this); + } + + return kapi::devices::device::query_interface(interface); + } + +} // namespace arch::devices \ No newline at end of file diff --git a/arch/x86_64/arch/devices/pit.hpp b/arch/x86_64/arch/devices/pit.hpp new file mode 100644 index 00000000..5104087b --- /dev/null +++ b/arch/x86_64/arch/devices/pit.hpp @@ -0,0 +1,32 @@ +#ifndef TEACHOS_ARCH_X86_64_DEVICES_PIT_HPP +#define TEACHOS_ARCH_X86_64_DEVICES_PIT_HPP + +#include + +#include + +#include + +namespace arch::devices +{ + + //! The ISA device for the legacy Programmable Interrupt Timer. + //! + //! This type identifies the PIT device node to the driver, so the driver can be matched successfully. + struct pit final : kapi::devices::device, arch::bus::isa_identification + { + //! Construct a new PIT device. + pit(); + + //! Get the synthetic ISA identifier for this device. + //! + //! @return the string "pit" + [[nodiscard]] auto isa_name() const -> std::string_view override; + + protected: + auto query_interface(kapi::devices::interface interface) -> void * override; + }; + +} // namespace arch::devices + +#endif \ No newline at end of file diff --git a/arch/x86_64/arch/drivers/init.cpp b/arch/x86_64/arch/drivers/init.cpp new file mode 100644 index 00000000..4878ea09 --- /dev/null +++ b/arch/x86_64/arch/drivers/init.cpp @@ -0,0 +1,27 @@ +#include + +#include + +#include + +#include + +#include + +namespace arch::drivers +{ + + namespace + { + //! The interrupt frequency of the Programmable Interrupt Timer. + constexpr auto pit_frequency_in_hz = std::uint32_t{100u}; + } // namespace + + auto init_legacy_drivers() -> void + { + auto & driver_registry = kapi::devices::driver_registry::get(); + + driver_registry.add(kstd::make_shared(pit_frequency_in_hz)); + } + +} // namespace arch::drivers diff --git a/arch/x86_64/arch/drivers/init.hpp b/arch/x86_64/arch/drivers/init.hpp new file mode 100644 index 00000000..797edb0f --- /dev/null +++ b/arch/x86_64/arch/drivers/init.hpp @@ -0,0 +1,11 @@ +#ifndef TEACHOS_ARCH_X86_64_DRIVERS_INIT_HPP +#define TEACHOS_ARCH_X86_64_DRIVERS_INIT_HPP + +namespace arch::drivers +{ + + auto init_legacy_drivers() -> void; + +} + +#endif diff --git a/arch/x86_64/arch/drivers/pit.cpp b/arch/x86_64/arch/drivers/pit.cpp new file mode 100644 index 00000000..2b03172d --- /dev/null +++ b/arch/x86_64/arch/drivers/pit.cpp @@ -0,0 +1,100 @@ +#include + +#include +#include + +#include +#include + +#include +#include + +#include +#include +#include +#include + +namespace arch::drivers +{ + + using namespace std::string_view_literals; + + namespace + { + using command_port = io::port<0x43, std::uint8_t, io::port_write>; + using channel_0_port = io::port<0x40, std::uint8_t, io::port_write>; + using channel_1_port = io::port<0x41, std::uint8_t, io::port_write>; + using channel_2_port = io::port<0x42, std::uint8_t, io::port_write>; + + constexpr auto base_frequency = 1'193'182u; + constexpr auto square_wave_mode = 0x36; + + constexpr auto pit_names = std::array{"pit"sv}; + } // namespace + + pit::pit(std::uint32_t frequency_in_hz) + : m_frequency_in_hz{frequency_in_hz} + {} + + auto pit::probe(kapi::devices::device & device) -> kstd::result + { + auto data = kstd::make_shared(0, 0); + device.set_driver_data(data); + + auto divisor = static_cast(base_frequency / m_frequency_in_hz); + + kapi::interrupts::register_handler(data->irq_number, *this, data); + + command_port::write(square_wave_mode); + io::wait(); + channel_0_port::write(divisor & 0xff); + io::wait(); + channel_0_port::write(divisor >> 8 & 0xff); + io::wait(); + + return kstd::success(); + } + + auto pit::unbind(kapi::devices::device & device) -> void + { + auto data = static_pointer_cast(device.driver_data()); + + kapi::interrupts::unregister_handler(data->irq_number, *this); + + device.set_driver_data(nullptr); + } + + auto pit::supported_names() const -> std::span + { + return pit_names; + } + + auto pit::handle_interrupt(std::uint32_t irq_number, kstd::weak_ptr context) -> kapi::interrupts::status + { + auto data = static_pointer_cast(context.lock()); + if (!data) + { + return kapi::interrupts::status::unhandled; + } + + if (irq_number != data->irq_number) + { + return kapi::interrupts::status::unhandled; + } + + ++data->ticks; + + return kapi::interrupts::status::handled; + } + + auto pit::query_interface(kapi::devices::interface interface) -> void * + { + if (interface == arch::bus::isa_driver_identification::id) + { + return static_cast(this); + } + + return kapi::devices::driver::query_interface(interface); + } + +} // namespace arch::drivers \ No newline at end of file diff --git a/arch/x86_64/arch/drivers/pit.hpp b/arch/x86_64/arch/drivers/pit.hpp new file mode 100644 index 00000000..f22c6037 --- /dev/null +++ b/arch/x86_64/arch/drivers/pit.hpp @@ -0,0 +1,47 @@ +#ifndef TEACHOS_ARCH_X86_64_DRIVERS_PIT_HPP +#define TEACHOS_ARCH_X86_64_DRIVERS_PIT_HPP + +#include + +#include +#include + +#include +#include + +#include +#include +#include + +namespace arch::drivers +{ + + //! The driver for the legacy, ISA-connected Programmable Interrupt Timer. + struct pit final : kapi::devices::driver, arch::bus::isa_driver_identification, kapi::interrupts::handler + { + explicit pit(std::uint32_t frequency_in_hz); + + [[nodiscard]] auto probe(kapi::devices::device & device) -> kstd::result override; + + auto unbind(kapi::devices::device & device) -> void override; + + [[nodiscard]] auto supported_names() const -> std::span override; + + auto handle_interrupt(std::uint32_t irq_number, kstd::weak_ptr context) -> kapi::interrupts::status override; + + protected: + auto query_interface(kapi::devices::interface interface) -> void * override; + + private: + struct data + { + std::uint32_t irq_number{}; + std::uint64_t ticks{}; + }; + + std::uint32_t m_frequency_in_hz{}; + }; + +} // namespace arch::drivers + +#endif \ No newline at end of file diff --git a/arch/x86_64/kapi/devices.cpp b/arch/x86_64/kapi/devices.cpp index f188c92b..748e0a6a 100644 --- a/arch/x86_64/kapi/devices.cpp +++ b/arch/x86_64/kapi/devices.cpp @@ -1,10 +1,16 @@ #include #include +#include namespace kapi::devices { + auto init_platform_drivers() -> void + { + arch::drivers::init_legacy_drivers(); + } + auto init_platform_devices() -> void { arch::devices::init_acpi_devices(); -- cgit v1.2.3