From b84c4c9d8c90f3d3fd5a60de282278912fad2f04 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Thu, 2 Apr 2026 13:59:27 +0200 Subject: x86_64/devices: implement ISA bus stub --- arch/x86_64/CMakeLists.txt | 4 +++ arch/x86_64/include/arch/bus/isa.hpp | 31 ++++++++++++++++++++ arch/x86_64/kapi/devices.cpp | 22 ++++++++++++++ arch/x86_64/src/bus/isa.cpp | 56 ++++++++++++++++++++++++++++++++++++ 4 files changed, 113 insertions(+) create mode 100644 arch/x86_64/include/arch/bus/isa.hpp create mode 100644 arch/x86_64/kapi/devices.cpp create mode 100644 arch/x86_64/src/bus/isa.cpp (limited to 'arch/x86_64') diff --git a/arch/x86_64/CMakeLists.txt b/arch/x86_64/CMakeLists.txt index 4427e4c..21dceef 100644 --- a/arch/x86_64/CMakeLists.txt +++ b/arch/x86_64/CMakeLists.txt @@ -15,6 +15,7 @@ target_sources("x86_64" PRIVATE "kapi/boot_modules.cpp" "kapi/cio.cpp" "kapi/cpu.cpp" + "kapi/devices.cpp" "kapi/interrupts.cpp" "kapi/memory.cpp" "kapi/system.cpp" @@ -24,6 +25,9 @@ target_sources("x86_64" PRIVATE "src/cpu/interrupts.cpp" "src/cpu/interrupt_stubs.S" + # Bus Initialization + "src/bus/isa.cpp" + # Low-level bootstrap "src/boot/boot32.S" "src/boot/entry64.s" diff --git a/arch/x86_64/include/arch/bus/isa.hpp b/arch/x86_64/include/arch/bus/isa.hpp new file mode 100644 index 0000000..41dda93 --- /dev/null +++ b/arch/x86_64/include/arch/bus/isa.hpp @@ -0,0 +1,31 @@ +#ifndef TEACHOS_X86_64_BUS_ISA_HPP +#define TEACHOS_X86_64_BUS_ISA_HPP + +#include "kapi/devices/bus.hpp" +#include "kapi/devices/device.hpp" + +#include +#include + +namespace arch::bus +{ + + struct isa final : public kapi::devices::bus + { + isa(); + + auto add_child(kstd::unique_ptr child) -> void override; + + [[nodiscard]] auto children() const -> kstd::vector> const & override; + + auto init() -> bool override; + + private: + kstd::vector> m_devices{}; + kstd::vector> m_observers{}; + bool m_initialized{}; + }; + +} // namespace arch::bus + +#endif // TEACHOS_X86_64_BUS_ISA_HPP diff --git a/arch/x86_64/kapi/devices.cpp b/arch/x86_64/kapi/devices.cpp new file mode 100644 index 0000000..25185d6 --- /dev/null +++ b/arch/x86_64/kapi/devices.cpp @@ -0,0 +1,22 @@ +#include "kapi/devices.hpp" + +#include "arch/bus/isa.hpp" + +#include +#include + +#include + +namespace kapi::devices +{ + + auto init_platform_devices() -> void + { + kstd::println("[x86_64:devices] Initializing ISA bus..."); + auto isa_bus = kstd::make_unique(); + + auto & root_bus = get_root_bus(); + root_bus.add_child(std::move(isa_bus)); + } + +} // namespace kapi::devices \ No newline at end of file diff --git a/arch/x86_64/src/bus/isa.cpp b/arch/x86_64/src/bus/isa.cpp new file mode 100644 index 0000000..3fe4f6f --- /dev/null +++ b/arch/x86_64/src/bus/isa.cpp @@ -0,0 +1,56 @@ +#include "arch/bus/isa.hpp" + +#include "kapi/devices.hpp" +#include "kapi/devices/device.hpp" +#include "kapi/system.hpp" + +#include +#include +#include + +#include +#include + +namespace arch::bus +{ + + isa::isa() + : kapi::devices::bus(kapi::devices::allocate_major_number(), 0, "isa") + {} + + auto isa::add_child(kstd::unique_ptr child) -> void + { + auto observer = m_observers.emplace_back(child.get()); + m_devices.push_back(std::move(child)); + + if (m_initialized) + { + kstd::println("[bus:{}} Initializing child device '{}'", name(), observer->name()); + if (!observer->init()) + { + kapi::system::panic("[x86_64:devices] Failed to initialize child device"); + } + } + } + + auto isa::children() const -> kstd::vector> const & + { + return m_observers; + } + + auto isa::init() -> bool + { + if (m_initialized) + { + kapi::system::panic("[x86_64:devices] ISA bus already initialized!"); + } + + m_initialized = std::ranges::fold_left(m_devices, true, [](bool acc, auto & child) -> bool { + kstd::println("[x86_64:devices] Initializing child device '{}'", child->name()); + return acc && child->init(); + }); + + return m_initialized; + } + +} // namespace arch::bus \ No newline at end of file -- cgit v1.2.3 From 66ffd2ad8c793c4eea1527848fe4772e42595718 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Thu, 2 Apr 2026 14:24:52 +0200 Subject: kapi: extract common bus code --- arch/x86_64/include/arch/bus/isa.hpp | 15 ------------ arch/x86_64/src/bus/isa.cpp | 44 ------------------------------------ 2 files changed, 59 deletions(-) (limited to 'arch/x86_64') diff --git a/arch/x86_64/include/arch/bus/isa.hpp b/arch/x86_64/include/arch/bus/isa.hpp index 41dda93..bd92b2e 100644 --- a/arch/x86_64/include/arch/bus/isa.hpp +++ b/arch/x86_64/include/arch/bus/isa.hpp @@ -2,10 +2,6 @@ #define TEACHOS_X86_64_BUS_ISA_HPP #include "kapi/devices/bus.hpp" -#include "kapi/devices/device.hpp" - -#include -#include namespace arch::bus { @@ -13,17 +9,6 @@ namespace arch::bus struct isa final : public kapi::devices::bus { isa(); - - auto add_child(kstd::unique_ptr child) -> void override; - - [[nodiscard]] auto children() const -> kstd::vector> const & override; - - auto init() -> bool override; - - private: - kstd::vector> m_devices{}; - kstd::vector> m_observers{}; - bool m_initialized{}; }; } // namespace arch::bus diff --git a/arch/x86_64/src/bus/isa.cpp b/arch/x86_64/src/bus/isa.cpp index 3fe4f6f..2ad4d21 100644 --- a/arch/x86_64/src/bus/isa.cpp +++ b/arch/x86_64/src/bus/isa.cpp @@ -1,15 +1,6 @@ #include "arch/bus/isa.hpp" #include "kapi/devices.hpp" -#include "kapi/devices/device.hpp" -#include "kapi/system.hpp" - -#include -#include -#include - -#include -#include namespace arch::bus { @@ -18,39 +9,4 @@ namespace arch::bus : kapi::devices::bus(kapi::devices::allocate_major_number(), 0, "isa") {} - auto isa::add_child(kstd::unique_ptr child) -> void - { - auto observer = m_observers.emplace_back(child.get()); - m_devices.push_back(std::move(child)); - - if (m_initialized) - { - kstd::println("[bus:{}} Initializing child device '{}'", name(), observer->name()); - if (!observer->init()) - { - kapi::system::panic("[x86_64:devices] Failed to initialize child device"); - } - } - } - - auto isa::children() const -> kstd::vector> const & - { - return m_observers; - } - - auto isa::init() -> bool - { - if (m_initialized) - { - kapi::system::panic("[x86_64:devices] ISA bus already initialized!"); - } - - m_initialized = std::ranges::fold_left(m_devices, true, [](bool acc, auto & child) -> bool { - kstd::println("[x86_64:devices] Initializing child device '{}'", child->name()); - return acc && child->init(); - }); - - return m_initialized; - } - } // namespace arch::bus \ No newline at end of file -- cgit v1.2.3 From ab4c59912c526d515e6e72188c08a7f92e5573e8 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Thu, 2 Apr 2026 15:07:54 +0200 Subject: x86_64: implement legacy PIT driver --- arch/x86_64/CMakeLists.txt | 3 ++ arch/x86_64/include/arch/devices/legacy_pit.hpp | 28 +++++++++++++ arch/x86_64/kapi/devices.cpp | 11 +++++ arch/x86_64/src/cpu/initialization.cpp | 2 +- arch/x86_64/src/devices/legacy_pit.cpp | 54 +++++++++++++++++++++++++ 5 files changed, 97 insertions(+), 1 deletion(-) create mode 100644 arch/x86_64/include/arch/devices/legacy_pit.hpp create mode 100644 arch/x86_64/src/devices/legacy_pit.cpp (limited to 'arch/x86_64') diff --git a/arch/x86_64/CMakeLists.txt b/arch/x86_64/CMakeLists.txt index 21dceef..83cae0b 100644 --- a/arch/x86_64/CMakeLists.txt +++ b/arch/x86_64/CMakeLists.txt @@ -37,6 +37,9 @@ target_sources("x86_64" PRIVATE # Debug interfaces "src/debug/qemu_output.cpp" + # Devices + "src/devices/legacy_pit.cpp" + # Memory management "src/memory/kernel_mapper.cpp" "src/memory/higher_half_mapper.cpp" diff --git a/arch/x86_64/include/arch/devices/legacy_pit.hpp b/arch/x86_64/include/arch/devices/legacy_pit.hpp new file mode 100644 index 0000000..d28e4d6 --- /dev/null +++ b/arch/x86_64/include/arch/devices/legacy_pit.hpp @@ -0,0 +1,28 @@ +#ifndef TEACHOS_ARCH_X86_64_DEVICES_LEGACY_PIT_HPP +#define TEACHOS_ARCH_X86_64_DEVICES_LEGACY_PIT_HPP + +#include "kapi/devices/device.hpp" +#include "kapi/interrupts.hpp" + +#include + +namespace arch::devices +{ + + struct legacy_pit : kapi::devices::device, kapi::interrupts::handler + { + explicit legacy_pit(std::uint32_t frequency_in_hz); + + auto init() -> bool override; + + auto handle_interrupt(std::uint32_t irq_number) -> kapi::interrupts::status override; + + private: + std::uint32_t m_irq_number{}; + std::uint32_t m_frequency_in_hz{}; + std::uint64_t m_ticks{}; + }; + +} // namespace arch::devices + +#endif \ No newline at end of file diff --git a/arch/x86_64/kapi/devices.cpp b/arch/x86_64/kapi/devices.cpp index 25185d6..7aa7090 100644 --- a/arch/x86_64/kapi/devices.cpp +++ b/arch/x86_64/kapi/devices.cpp @@ -1,20 +1,31 @@ #include "kapi/devices.hpp" #include "arch/bus/isa.hpp" +#include "arch/devices/legacy_pit.hpp" #include #include +#include #include namespace kapi::devices { + namespace + { + constexpr auto pit_frequency_in_hz = std::uint32_t{100u}; + } + auto init_platform_devices() -> void { kstd::println("[x86_64:devices] Initializing ISA bus..."); + auto isa_bus = kstd::make_unique(); + auto pit = kstd::make_unique(pit_frequency_in_hz); + isa_bus->add_child(std::move(pit)); + auto & root_bus = get_root_bus(); root_bus.add_child(std::move(isa_bus)); } diff --git a/arch/x86_64/src/cpu/initialization.cpp b/arch/x86_64/src/cpu/initialization.cpp index 878fa07..b808c76 100644 --- a/arch/x86_64/src/cpu/initialization.cpp +++ b/arch/x86_64/src/cpu/initialization.cpp @@ -139,7 +139,7 @@ namespace arch::cpu constexpr auto pic_cascade_address = std::uint8_t{0x04}; constexpr auto pic_cascade_slave_identity = std::uint8_t{0x02}; constexpr auto pic_use_8086_mode = std::uint8_t{0x01}; - constexpr auto pic_master_mask = std::uint8_t{0x01}; + constexpr auto pic_master_mask = std::uint8_t{0x00}; constexpr auto pic_slave_mask = std::uint8_t{0x00}; pic_master_control_port::write(pic_init_command); diff --git a/arch/x86_64/src/devices/legacy_pit.cpp b/arch/x86_64/src/devices/legacy_pit.cpp new file mode 100644 index 0000000..f2fb70e --- /dev/null +++ b/arch/x86_64/src/devices/legacy_pit.cpp @@ -0,0 +1,54 @@ +#include "arch/devices/legacy_pit.hpp" + +#include "kapi/devices.hpp" +#include "kapi/devices/device.hpp" +#include "kapi/interrupts.hpp" + +#include "arch/device_io/port_io.hpp" + +#include + +namespace arch::devices +{ + + 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>; + } // namespace + + legacy_pit::legacy_pit(std::uint32_t frequency_in_hz) + : kapi::devices::device{kapi::devices::allocate_major_number(), 0, "legacy_pit"} + , m_irq_number{0} + , m_frequency_in_hz{frequency_in_hz} + {} + + auto legacy_pit::init() -> bool + { + constexpr auto base_frequency = 1'193'182u; + auto divisor = static_cast(base_frequency / m_frequency_in_hz); + + kapi::interrupts::register_handler(m_irq_number, *this); + + command_port::write(0x36); // NOLINT + channel_0_port::write(divisor & 0xff); // NOLINT + channel_0_port::write(divisor >> 8 & 0xff); // NOLINT + + return true; + } + + auto legacy_pit::handle_interrupt(std::uint32_t irq_number) -> kapi::interrupts::status + { + if (irq_number != m_irq_number) + { + return kapi::interrupts::status::unhandled; + } + + ++m_ticks; + + return kapi::interrupts::status::handled; + } + +} // namespace arch::devices \ No newline at end of file -- cgit v1.2.3 From 21489576381d827871e7cdf060929c5d7f3d4e9f Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Thu, 2 Apr 2026 15:49:14 +0200 Subject: devices: don't automatically allocate major numbers in ctors --- arch/x86_64/include/arch/bus/isa.hpp | 4 +++- arch/x86_64/include/arch/devices/legacy_pit.hpp | 3 ++- arch/x86_64/kapi/devices.cpp | 6 ++++-- arch/x86_64/src/bus/isa.cpp | 6 ++++-- arch/x86_64/src/devices/legacy_pit.cpp | 5 +++-- 5 files changed, 16 insertions(+), 8 deletions(-) (limited to 'arch/x86_64') diff --git a/arch/x86_64/include/arch/bus/isa.hpp b/arch/x86_64/include/arch/bus/isa.hpp index bd92b2e..5deed25 100644 --- a/arch/x86_64/include/arch/bus/isa.hpp +++ b/arch/x86_64/include/arch/bus/isa.hpp @@ -3,12 +3,14 @@ #include "kapi/devices/bus.hpp" +#include + namespace arch::bus { struct isa final : public kapi::devices::bus { - isa(); + isa(std::size_t major); }; } // namespace arch::bus diff --git a/arch/x86_64/include/arch/devices/legacy_pit.hpp b/arch/x86_64/include/arch/devices/legacy_pit.hpp index d28e4d6..de742ae 100644 --- a/arch/x86_64/include/arch/devices/legacy_pit.hpp +++ b/arch/x86_64/include/arch/devices/legacy_pit.hpp @@ -4,6 +4,7 @@ #include "kapi/devices/device.hpp" #include "kapi/interrupts.hpp" +#include #include namespace arch::devices @@ -11,7 +12,7 @@ namespace arch::devices struct legacy_pit : kapi::devices::device, kapi::interrupts::handler { - explicit legacy_pit(std::uint32_t frequency_in_hz); + legacy_pit(std::size_t major, std::uint32_t frequency_in_hz); auto init() -> bool override; diff --git a/arch/x86_64/kapi/devices.cpp b/arch/x86_64/kapi/devices.cpp index 7aa7090..b15503d 100644 --- a/arch/x86_64/kapi/devices.cpp +++ b/arch/x86_64/kapi/devices.cpp @@ -21,9 +21,11 @@ namespace kapi::devices { kstd::println("[x86_64:devices] Initializing ISA bus..."); - auto isa_bus = kstd::make_unique(); + auto isa_major_number = kapi::devices::allocate_major_number(); + auto isa_bus = kstd::make_unique(isa_major_number); - auto pit = kstd::make_unique(pit_frequency_in_hz); + auto pit_major_number = kapi::devices::allocate_major_number(); + auto pit = kstd::make_unique(pit_major_number, pit_frequency_in_hz); isa_bus->add_child(std::move(pit)); auto & root_bus = get_root_bus(); diff --git a/arch/x86_64/src/bus/isa.cpp b/arch/x86_64/src/bus/isa.cpp index 2ad4d21..ff4ad71 100644 --- a/arch/x86_64/src/bus/isa.cpp +++ b/arch/x86_64/src/bus/isa.cpp @@ -2,11 +2,13 @@ #include "kapi/devices.hpp" +#include + namespace arch::bus { - isa::isa() - : kapi::devices::bus(kapi::devices::allocate_major_number(), 0, "isa") + isa::isa(std::size_t major) + : kapi::devices::bus{major, 0, "isa"} {} } // namespace arch::bus \ No newline at end of file diff --git a/arch/x86_64/src/devices/legacy_pit.cpp b/arch/x86_64/src/devices/legacy_pit.cpp index f2fb70e..970f538 100644 --- a/arch/x86_64/src/devices/legacy_pit.cpp +++ b/arch/x86_64/src/devices/legacy_pit.cpp @@ -6,6 +6,7 @@ #include "arch/device_io/port_io.hpp" +#include #include namespace arch::devices @@ -19,8 +20,8 @@ namespace arch::devices using channel_2_port = io::port<0x42, std::uint8_t, io::port_write>; } // namespace - legacy_pit::legacy_pit(std::uint32_t frequency_in_hz) - : kapi::devices::device{kapi::devices::allocate_major_number(), 0, "legacy_pit"} + legacy_pit::legacy_pit(std::size_t major, std::uint32_t frequency_in_hz) + : kapi::devices::device{major, 0, "legacy_pit"} , m_irq_number{0} , m_frequency_in_hz{frequency_in_hz} {} -- cgit v1.2.3 From c5afb5c1ce1c084c840dbb58d73af6fe2b235ec7 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Thu, 2 Apr 2026 15:55:47 +0200 Subject: x86_64: ensure PIT is not overwhelmed on config --- arch/x86_64/include/arch/device_io/port_io.hpp | 5 +++++ arch/x86_64/src/devices/legacy_pit.cpp | 13 +++++++++---- 2 files changed, 14 insertions(+), 4 deletions(-) (limited to 'arch/x86_64') diff --git a/arch/x86_64/include/arch/device_io/port_io.hpp b/arch/x86_64/include/arch/device_io/port_io.hpp index 70773dd..4c8d66a 100644 --- a/arch/x86_64/include/arch/device_io/port_io.hpp +++ b/arch/x86_64/include/arch/device_io/port_io.hpp @@ -102,6 +102,11 @@ namespace arch::io : std::string_view{"eax"}; }; + auto inline wait() -> void + { + port<0x80, std::uint8_t, port_write>::write(0); + } + } // namespace arch::io #endif \ No newline at end of file diff --git a/arch/x86_64/src/devices/legacy_pit.cpp b/arch/x86_64/src/devices/legacy_pit.cpp index 970f538..a8df3c3 100644 --- a/arch/x86_64/src/devices/legacy_pit.cpp +++ b/arch/x86_64/src/devices/legacy_pit.cpp @@ -18,6 +18,9 @@ namespace arch::devices 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; } // namespace legacy_pit::legacy_pit(std::size_t major, std::uint32_t frequency_in_hz) @@ -28,14 +31,16 @@ namespace arch::devices auto legacy_pit::init() -> bool { - constexpr auto base_frequency = 1'193'182u; auto divisor = static_cast(base_frequency / m_frequency_in_hz); kapi::interrupts::register_handler(m_irq_number, *this); - command_port::write(0x36); // NOLINT - channel_0_port::write(divisor & 0xff); // NOLINT - channel_0_port::write(divisor >> 8 & 0xff); // NOLINT + 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 true; } -- cgit v1.2.3