diff options
| author | Felix Morgner <felix.morgner@ost.ch> | 2026-07-28 13:09:08 +0200 |
|---|---|---|
| committer | Felix Morgner <felix.morgner@ost.ch> | 2026-07-28 13:09:08 +0200 |
| commit | 36248bb63a396dfea762d5b2cf028bf4b7a2b62e (patch) | |
| tree | b05726555a387b719292a4d19c4c4a5cbc7e31cc | |
| parent | b5450cecbffdca1dd9dffdb58dd295a6a5d7f6eb (diff) | |
| download | kernel-36248bb63a396dfea762d5b2cf028bf4b7a2b62e.tar.xz kernel-36248bb63a396dfea762d5b2cf028bf4b7a2b62e.zip | |
x86_64: split lapic according to UDM
29 files changed, 604 insertions, 313 deletions
diff --git a/arch/x86_64/CMakeLists.txt b/arch/x86_64/CMakeLists.txt index 4e4fc52a..30c84b16 100644 --- a/arch/x86_64/CMakeLists.txt +++ b/arch/x86_64/CMakeLists.txt @@ -31,6 +31,7 @@ target_sources("x86_64" PRIVATE "arch/cpu/interrupts.S" # Bus Initialization + "arch/bus/cpu.cpp" "arch/bus/isa.cpp" # Low-level bootstrap @@ -45,10 +46,12 @@ target_sources("x86_64" PRIVATE # Devices "arch/devices/init.cpp" "arch/devices/pit.cpp" - "arch/devices/local_apic.cpp" + "arch/devices/cpu/core.cpp" + "arch/devices/cpu/lapic.cpp" # Drivers "arch/drivers/init.cpp" + "arch/drivers/lapic.cpp" "arch/drivers/pit.cpp" # Memory management diff --git a/arch/x86_64/arch/bus/cpu.cpp b/arch/x86_64/arch/bus/cpu.cpp new file mode 100644 index 00000000..3b5f9804 --- /dev/null +++ b/arch/x86_64/arch/bus/cpu.cpp @@ -0,0 +1,109 @@ +#include <arch/bus/cpu.hpp> + +#include <arch/devices/cpu/core.hpp> +#include <arch/devices/cpu/lapic.hpp> + +#include <kapi/acpi.hpp> +#include <kapi/devices.hpp> +#include <kapi/memory.hpp> + +#include <acpi/acpi.hpp> + +#include <kstd/format.hpp> +#include <kstd/memory.hpp> +#include <kstd/print.hpp> +#include <kstd/result.hpp> +#include <kstd/units.hpp> + +#include <cstdint> +#include <ranges> + +namespace arch::bus +{ + + namespace + { + constexpr auto candidate_flags = ::acpi::processor_local_apic_entry::flags::processor_enabled // + | ::acpi::processor_local_apic_entry::flags::online_capable; + + constexpr auto lapic_mmio_range_size = kstd::units::bytes{0x400}; + + struct protocol final : kapi::devices::bus_protocol + { + auto enumerate(kapi::devices::bus & bus) -> void override + { + auto madt = kapi::acpi::get_table<::acpi::table_signature_v<::acpi::madt>>(); + if (!madt) + { + kstd::println("[x86_64:BUS] Failed to find ACPI APIC table"); + return; + } + + auto lapic_entries = *madt | std::views::filter([](auto const & entry) { + return entry.type() == ::acpi::madt_entry::type::processor_local_apic; + }) | std::views::transform([](auto const & entry) { + return static_cast<::acpi::processor_local_apic_entry const &>(entry); + }) | std::views::filter([](auto const & entry) { return static_cast<bool>(entry.flags() & candidate_flags); }); + + auto bsp_found = false; + auto local_apic_address = kapi::memory::physical_address{madt->local_interrupt_controller_address()}; + + for (auto const & entry : std::views::enumerate(lapic_entries)) + { + auto [index, apic] = entry; + auto is_bsp = !bsp_found; + + auto core = kstd::make_shared<devices::cpu::core>(index, apic.processor_id(), is_bsp); + bus.add_child(core); + + auto lapic = kstd::make_shared<devices::cpu::lapic>(index, apic.id(), is_bsp); + auto lapic_range = kapi::devices::mmio_range{.start = local_apic_address, .size = lapic_mmio_range_size}; + lapic->set_resources({kapi::devices::resource{lapic_range}}); + bus.add_child(lapic); + + bsp_found = true; + } + } + + [[nodiscard]] auto match(kapi::devices::device const & device, kapi::devices::driver const & driver) const + -> kstd::result<std::uint32_t> override + { + return try_match_core(device, driver).or_else([&](auto) { return try_match_lapic(device, driver); }); + } + + private: + [[nodiscard]] auto try_match_core(kapi::devices::device const & device, + kapi::devices::driver const & driver) const -> kstd::result<std::uint32_t> + { + auto signature = device.facet<core_signature>(); + auto claim = driver.facet<core_claim>(); + + if (!signature || !claim) + { + return kstd::failure(kapi::devices::driver_match_errc::no_match); + } + + return 0u; + } + + [[nodiscard]] auto try_match_lapic(kapi::devices::device const & device, + kapi::devices::driver const & driver) const -> kstd::result<std::uint32_t> + { + auto signature = device.facet<lapic_signature>(); + auto claim = driver.facet<lapic_claim>(); + + if (!signature || !claim) + { + return kstd::failure(kapi::devices::driver_match_errc::no_match); + } + + return 0u; + } + } constinit protocol_instance; + } // namespace + + cpu::cpu() + : bus{"cpu", protocol_instance} + {} + +} // namespace arch::bus diff --git a/arch/x86_64/arch/bus/cpu.hpp b/arch/x86_64/arch/bus/cpu.hpp new file mode 100644 index 00000000..c4378493 --- /dev/null +++ b/arch/x86_64/arch/bus/cpu.hpp @@ -0,0 +1,76 @@ +#ifndef TEACHOS_ARCH_X86_64_BUS_CPU_HPP +#define TEACHOS_ARCH_X86_64_BUS_CPU_HPP + +#include <kapi/capabilities/facet_id.hpp> +#include <kapi/devices.hpp> + +#include <kstd/result.hpp> + +#include <cstdint> +#include <string_view> + +namespace arch::bus +{ + + //! The signature facet used to identify CPU bus devices. + struct core_signature + { + //! The ID of this facet. + constexpr auto static id = kapi::capabilities::facet_id{"core_signature"}; + + //! Allow for correct destruction through base pointers. + virtual ~core_signature() = default; + + //! Whether this core is the bootstrap processor. + [[nodiscard]] virtual auto is_bsp() const noexcept -> bool = 0; + + //! The ID of this core. + [[nodiscard]] virtual auto hardware_id() const noexcept -> std::uint64_t = 0; + }; + + //! The claim facet used to match ISA drivers. + struct core_claim + { + //! The ID of this facet + constexpr auto static id = kapi::capabilities::facet_id{"core_claim"}; + + //! Allow for correct destruction through base pointers. + virtual ~core_claim() = default; + }; + + //! The signature to identify a core-local interrupt controller (local APIC) device. + struct lapic_signature + { + //! The ID of this facet. + constexpr auto static id = kapi::capabilities::facet_id{"lapic_signature"}; + + //! Allow for correct destruction through base pointers. + virtual ~lapic_signature() = default; + + //! The local APIC's own hardware identifier. + [[nodiscard]] virtual auto hardware_id() const noexcept -> std::uint64_t = 0; + + //! Whether this local APIC belongs to the bootstrap processor. + [[nodiscard]] virtual auto belongs_to_bsp() const noexcept -> bool = 0; + }; + + //! The claim facet used to match the local APIC driver against a local APIC device. + struct lapic_claim + { + //! The ID of this facet. + constexpr auto static id = kapi::capabilities::facet_id{"lapic_claim"}; + + //! Allow for correct destruction through base pointers. + virtual ~lapic_claim() = default; + }; + + //! The CPU bus. + struct cpu final : public kapi::devices::bus + { + //! Construct a default CPU bus. + cpu(); + }; + +} // namespace arch::bus + +#endif // TEACHOS_X86_64_BUS_ISA_HPP diff --git a/arch/x86_64/arch/cpu/legacy_pic.hpp b/arch/x86_64/arch/cpu/legacy_pic.hpp index 56ca9c44..5fcaecac 100644 --- a/arch/x86_64/arch/cpu/legacy_pic.hpp +++ b/arch/x86_64/arch/cpu/legacy_pic.hpp @@ -1,7 +1,7 @@ #ifndef TEACHOS_X86_64_CPU_LEGACY_PIC_HPP #define TEACHOS_X86_64_CPU_LEGACY_PIC_HPP -#include <arch/device_io/port_io.hpp> +#include <arch/io/port_io.hpp> #include <cstdint> diff --git a/arch/x86_64/arch/devices/cpu/core.cpp b/arch/x86_64/arch/devices/cpu/core.cpp new file mode 100644 index 00000000..ac06850e --- /dev/null +++ b/arch/x86_64/arch/devices/cpu/core.cpp @@ -0,0 +1,42 @@ +#include <arch/devices/cpu/core.hpp> + +#include <arch/bus/cpu.hpp> + +#include <kapi/capabilities/facet_id.hpp> +#include <kapi/devices.hpp> + +#include <kstd/format.hpp> + +#include <cstddef> +#include <cstdint> + +namespace arch::devices::cpu +{ + + core::core(std::size_t index, std::uint64_t id, bool is_bsp) + : device{kstd::format("core{}", index)} + , m_id{id} + , m_is_bsp{is_bsp} + {} + + auto core::is_bsp() const noexcept -> bool + { + return m_is_bsp; + } + + auto core::hardware_id() const noexcept -> std::uint64_t + { + return m_id; + } + + auto core::query_facet(kapi::capabilities::facet_id facet) -> void * + { + if (facet == bus::core_signature::id) + { + return static_cast<bus::core_signature *>(this); + } + + return device::query_facet(facet); + } + +} // namespace arch::devices::cpu diff --git a/arch/x86_64/arch/devices/cpu/core.hpp b/arch/x86_64/arch/devices/cpu/core.hpp new file mode 100644 index 00000000..64c3ed17 --- /dev/null +++ b/arch/x86_64/arch/devices/cpu/core.hpp @@ -0,0 +1,34 @@ +#ifndef TEACHOS_ARCH_X86_64_DEVICES_CPU_CORE_HPP +#define TEACHOS_ARCH_X86_64_DEVICES_CPU_CORE_HPP + +#include <arch/bus/cpu.hpp> + +#include <kapi/capabilities/facet_id.hpp> +#include <kapi/devices.hpp> + +#include <cstddef> +#include <cstdint> + +namespace arch::devices::cpu +{ + + struct core final : kapi::devices::device, arch::bus::core_signature + { + core(std::size_t index, std::uint64_t id, bool is_bsp); + + [[nodiscard]] auto is_bsp() const noexcept -> bool override; + [[nodiscard]] auto hardware_id() const noexcept -> std::uint64_t override; + + protected: + auto query_facet(kapi::capabilities::facet_id facet) -> void * override; + + private: + std::uint64_t m_id; + bool m_is_bsp; + + public: + }; + +} // namespace arch::devices::cpu + +#endif diff --git a/arch/x86_64/arch/devices/cpu/lapic.cpp b/arch/x86_64/arch/devices/cpu/lapic.cpp new file mode 100644 index 00000000..3abb18e6 --- /dev/null +++ b/arch/x86_64/arch/devices/cpu/lapic.cpp @@ -0,0 +1,42 @@ +#include <arch/devices/cpu/lapic.hpp> + +#include <arch/bus/cpu.hpp> + +#include <kapi/capabilities/facet_id.hpp> +#include <kapi/devices.hpp> + +#include <kstd/format.hpp> + +#include <cstddef> +#include <cstdint> + +namespace arch::devices::cpu +{ + + lapic::lapic(std::size_t index, std::uint64_t id, bool on_bsp) + : device{kstd::format("lapic{}", index)} + , m_id{id} + , m_belongs_to_bsp{on_bsp} + {} + + auto lapic::hardware_id() const noexcept -> std::uint64_t + { + return m_id; + } + + auto lapic::belongs_to_bsp() const noexcept -> bool + { + return m_belongs_to_bsp; + } + + auto lapic::query_facet(kapi::capabilities::facet_id facet) -> void * + { + if (facet == bus::lapic_signature::id) + { + return static_cast<bus::lapic_signature *>(this); + } + + return device::query_facet(facet); + } + +} // namespace arch::devices::cpu diff --git a/arch/x86_64/arch/devices/cpu/lapic.hpp b/arch/x86_64/arch/devices/cpu/lapic.hpp new file mode 100644 index 00000000..10dc71f3 --- /dev/null +++ b/arch/x86_64/arch/devices/cpu/lapic.hpp @@ -0,0 +1,32 @@ +#ifndef TEACHOS_ARCH_X86_64_DEVICES_CPU_LAPIC_HPP +#define TEACHOS_ARCH_X86_64_DEVICES_CPU_LAPIC_HPP + +#include <arch/bus/cpu.hpp> + +#include <kapi/capabilities/facet_id.hpp> +#include <kapi/devices.hpp> + +#include <cstddef> +#include <cstdint> + +namespace arch::devices::cpu +{ + + struct lapic final : kapi::devices::device, arch::bus::lapic_signature + { + lapic(std::size_t index, std::uint64_t id, bool on_bsp); + + [[nodiscard]] auto hardware_id() const noexcept -> std::uint64_t override; + [[nodiscard]] auto belongs_to_bsp() const noexcept -> bool override; + + protected: + auto query_facet(kapi::capabilities::facet_id facet) -> void * override; + + private: + std::uint64_t m_id; + bool m_belongs_to_bsp; + }; + +} // namespace arch::devices::cpu + +#endif diff --git a/arch/x86_64/arch/devices/init.cpp b/arch/x86_64/arch/devices/init.cpp index e73ffa59..9c20d413 100644 --- a/arch/x86_64/arch/devices/init.cpp +++ b/arch/x86_64/arch/devices/init.cpp @@ -5,7 +5,6 @@ #include <arch/devices/pit.hpp> #include <kapi/acpi.hpp> -#include <kapi/cpu.hpp> #include <kapi/devices.hpp> #include <acpi/acpi.hpp> @@ -51,7 +50,7 @@ namespace arch::devices } } - kapi::cpu::discover_topology(); + kapi::devices::discover_cpu_topology(); } auto init_legacy_devices() -> void diff --git a/arch/x86_64/arch/devices/local_apic.cpp b/arch/x86_64/arch/devices/local_apic.cpp deleted file mode 100644 index 2b32c864..00000000 --- a/arch/x86_64/arch/devices/local_apic.cpp +++ /dev/null @@ -1,136 +0,0 @@ -#include <arch/devices/local_apic.hpp> - -#include <kapi/devices.hpp> -#include <kapi/memory.hpp> - -#include <kstd/format.hpp> -#include <kstd/print.hpp> - -#include <cstddef> -#include <cstdint> -#include <utility> - -namespace arch::devices -{ - - namespace - { - constexpr auto lapic_enable_bit = 0x100u; - constexpr auto spurious_interrupt_vector = 0xFFu; - - constexpr auto offset_of_version = 0u; - constexpr auto offset_of_max_lvt_entry = 16u; - constexpr auto offset_of_eoi_suppression = 24u; - - } // namespace - - enum struct local_apic::registers : std::ptrdiff_t - { - id = 0x020, - version = 0x030, - task_priority = 0x080, - arbitration_priority = 0x090, - processor_priority = 0x0a0, - eoi = 0x0b0, - remote_read = 0x0c0, - logical_destination = 0x0d0, - destination_format = 0x0e0, - spurious_interrupt_vector = 0x0f0, - in_service_0 = 0x100, - in_service_1 = 0x110, - in_service_2 = 0x120, - in_service_3 = 0x130, - in_service_4 = 0x140, - in_service_5 = 0x150, - in_service_6 = 0x160, - in_service_7 = 0x170, - trigger_mode_0 = 0x180, - trigger_mode_1 = 0x190, - trigger_mode_2 = 0x1a0, - trigger_mode_3 = 0x1b0, - trigger_mode_4 = 0x1c0, - trigger_mode_5 = 0x1d0, - trigger_mode_6 = 0x1e0, - trigger_mode_7 = 0x1f0, - interrupt_request_0 = 0x200, - interrupt_request_1 = 0x210, - interrupt_request_2 = 0x220, - interrupt_request_3 = 0x230, - interrupt_request_4 = 0x240, - interrupt_request_5 = 0x250, - interrupt_request_6 = 0x260, - interrupt_request_7 = 0x270, - error_status = 0x280, - lvt_corrected_machine_check_interrupt = 0x2f0, - interrupt_command_0 = 0x300, - interrupt_command_1 = 0x310, - lvt_timer = 0x320, - lvt_thermal_sensors = 0x330, - lvt_performance_monitoring_counters = 0x340, - lvt_local_interrupt_0 = 0x350, - lvt_local_interrupt_1 = 0x360, - lvt_error = 0x370, - initial_count = 0x380, - current_count = 0x390, - divide_configuration = 0x3e0, - }; - - local_apic::local_apic(std::uint64_t core_index, std::uint64_t hardware_id, kapi::memory::physical_address base, - bool is_bsp) - : kapi::devices::device{kstd::format("lapic{}", core_index)} - , m_core_index{core_index} - , m_hardware_id{hardware_id} - , m_base{base} - , m_is_bsp{is_bsp} - { - auto static shared_virtual_base = kapi::memory::allocate_mmio_region(1); - auto static is_mapped = false; - - if (!is_mapped) - { - if (!kapi::memory::map_mmio_region(shared_virtual_base, m_base, kapi::memory::page_mapper::flags::writable)) - { - kstd::println("[x86_64:DEV] LAPIC {} MMIO mapping failed!", m_hardware_id); - return; - } - is_mapped = true; - } - - m_mapped_region = shared_virtual_base; - - if (m_is_bsp) - { - auto raw_version = read_register(registers::version); - m_version = (raw_version >> offset_of_version) & 0xff; - m_highest_lvt_entry_index = (raw_version >> offset_of_max_lvt_entry) & 0xff; - m_supports_eoi_broadcast_suppression = (raw_version >> offset_of_eoi_suppression) & 0x1; - - write_register(registers::spurious_interrupt_vector, lapic_enable_bit | spurious_interrupt_vector); - - kstd::println("[x86_64:DEV] LAPIC initialized. version: {#x} | max_lvt_entry: {} | eoi_suppression: {:s}", - m_version, m_highest_lvt_entry_index, m_supports_eoi_broadcast_suppression); - } - else - { - kstd::println("[x86_64:DEV] LAPIC {} is not on the BSP, deferring initialization.", m_hardware_id); - } - } - - auto local_apic::core_index() const noexcept -> std::uint64_t - { - return m_core_index; - } - - auto local_apic::read_register(registers id) const -> std::uint32_t - { - auto reg = static_cast<std::uint32_t volatile *>(m_mapped_region.first + std::to_underlying(id)); - return *reg; - } - - auto local_apic::write_register(registers id, std::uint32_t value) -> void - { - auto reg = static_cast<std::uint32_t volatile *>(m_mapped_region.first + std::to_underlying(id)); - *reg = value; - } - -} // namespace arch::devices diff --git a/arch/x86_64/arch/devices/local_apic.hpp b/arch/x86_64/arch/devices/local_apic.hpp deleted file mode 100644 index 61fc99be..00000000 --- a/arch/x86_64/arch/devices/local_apic.hpp +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_DEVICES_LOCAL_APIC_HPP -#define TEACHOS_ARCH_X86_64_DEVICES_LOCAL_APIC_HPP - -#include <kapi/devices/device.hpp> -#include <kapi/memory.hpp> - -#include <cstddef> -#include <cstdint> - -namespace arch::devices -{ - - struct local_apic : kapi::devices::device - { - local_apic(std::uint64_t core_index, std::uint64_t hardware_id, kapi::memory::physical_address base, bool is_bsp); - - [[nodiscard]] auto core_index() const noexcept -> std::uint64_t; - - private: - enum struct registers : std::ptrdiff_t; - - [[nodiscard]] auto read_register(registers id) const -> std::uint32_t; - auto write_register(registers id, std::uint32_t value) -> void; - - std::uint64_t m_core_index{}; - std::uint64_t m_hardware_id{}; - kapi::memory::physical_address m_base{}; - kapi::memory::mmio_region m_mapped_region{}; - bool m_is_bsp{}; - std::uint8_t m_version{}; - std::uint8_t m_highest_lvt_entry_index{}; - bool m_supports_eoi_broadcast_suppression{}; - }; - -} // namespace arch::devices - -#endif diff --git a/arch/x86_64/arch/devices/pit.cpp b/arch/x86_64/arch/devices/pit.cpp index bfd6e84b..83443c93 100644 --- a/arch/x86_64/arch/devices/pit.cpp +++ b/arch/x86_64/arch/devices/pit.cpp @@ -2,6 +2,7 @@ #include <arch/bus/isa.hpp> +#include <kapi/capabilities/facet_id.hpp> #include <kapi/devices.hpp> #include <string_view> diff --git a/arch/x86_64/arch/drivers/init.cpp b/arch/x86_64/arch/drivers/init.cpp index 4878ea09..0027336b 100644 --- a/arch/x86_64/arch/drivers/init.cpp +++ b/arch/x86_64/arch/drivers/init.cpp @@ -1,5 +1,6 @@ #include <arch/drivers/init.hpp> +#include <arch/drivers/lapic.hpp> #include <arch/drivers/pit.hpp> #include <kapi/devices.hpp> @@ -22,6 +23,7 @@ namespace arch::drivers auto & driver_registry = kapi::devices::driver_registry::get(); driver_registry.add(kstd::make_shared<pit>(pit_frequency_in_hz)); + driver_registry.add(kstd::make_shared<lapic>()); } } // namespace arch::drivers diff --git a/arch/x86_64/arch/drivers/lapic.cpp b/arch/x86_64/arch/drivers/lapic.cpp new file mode 100644 index 00000000..86d851f9 --- /dev/null +++ b/arch/x86_64/arch/drivers/lapic.cpp @@ -0,0 +1,167 @@ +#include <arch/drivers/lapic.hpp> + +#include <arch/bus/cpu.hpp> + +#include <kapi/capabilities/facet_id.hpp> +#include <kapi/devices.hpp> +#include <kapi/memory.hpp> + +#include <kstd/format.hpp> +#include <kstd/mutex.hpp> +#include <kstd/print.hpp> +#include <kstd/result.hpp> +#include <kstd/system_error.hpp> +#include <kstd/units.hpp> + +#include <cstddef> +#include <cstdint> +#include <string_view> +#include <utility> + +namespace arch::drivers +{ + + using namespace kstd::units_literals; + + namespace + { + constexpr auto lapic_enable_bit = 0x100u; + constexpr auto spurious_interrupt_vector = 0xFFu; + + constexpr auto offset_of_version = 0u; + constexpr auto offset_of_max_lvt_entry = 16u; + constexpr auto offset_of_eoi_suppression = 24u; + } // namespace + + enum struct lapic::registers : std::ptrdiff_t + { + id = 0x020, + version = 0x030, + task_priority = 0x080, + arbitration_priority = 0x090, + processor_priority = 0x0a0, + eoi = 0x0b0, + remote_read = 0x0c0, + logical_destination = 0x0d0, + destination_format = 0x0e0, + spurious_interrupt_vector = 0x0f0, + in_service_0 = 0x100, + in_service_1 = 0x110, + in_service_2 = 0x120, + in_service_3 = 0x130, + in_service_4 = 0x140, + in_service_5 = 0x150, + in_service_6 = 0x160, + in_service_7 = 0x170, + trigger_mode_0 = 0x180, + trigger_mode_1 = 0x190, + trigger_mode_2 = 0x1a0, + trigger_mode_3 = 0x1b0, + trigger_mode_4 = 0x1c0, + trigger_mode_5 = 0x1d0, + trigger_mode_6 = 0x1e0, + trigger_mode_7 = 0x1f0, + interrupt_request_0 = 0x200, + interrupt_request_1 = 0x210, + interrupt_request_2 = 0x220, + interrupt_request_3 = 0x230, + interrupt_request_4 = 0x240, + interrupt_request_5 = 0x250, + interrupt_request_6 = 0x260, + interrupt_request_7 = 0x270, + error_status = 0x280, + lvt_corrected_machine_check_interrupt = 0x2f0, + interrupt_command_0 = 0x300, + interrupt_command_1 = 0x310, + lvt_timer = 0x320, + lvt_thermal_sensors = 0x330, + lvt_performance_monitoring_counters = 0x340, + lvt_local_interrupt_0 = 0x350, + lvt_local_interrupt_1 = 0x360, + lvt_error = 0x370, + initial_count = 0x380, + current_count = 0x390, + divide_configuration = 0x3e0, + }; + + auto lapic::probe(kapi::devices::device & device) -> kstd::result<void> + { + auto * signature = device.facet<arch::bus::lapic_signature>(); + if (!signature) + { + return kstd::failure(make_error_code(kstd::errc::invalid_argument)); + } + + auto mmio = device.request_resource<kapi::devices::resource_type::mmio>(); + if (!mmio) + { + return kstd::failure(mmio.error()); + } + + auto guard = kstd::lock_guard{m_lock}; + + if (!m_is_mapped) + { + auto const page_count = (mmio->size + kapi::memory::page_size - 1_B) / kapi::memory::page_size; + m_mapped_region = kapi::memory::allocate_mmio_region(page_count); + + if (!kapi::memory::map_mmio_region(m_mapped_region, kapi::memory::physical_address{mmio->start}, + kapi::memory::page_mapper::flags::writable)) + { + kstd::println(kstd::print_sink::stderr, "[x86_64:DRV] LAPIC {} MMIO mapping failed!", signature->hardware_id()); + return kstd::failure(make_error_code(kstd::errc::io_error)); + } + + m_is_mapped = true; + } + + if (signature->belongs_to_bsp()) + { + auto raw_version = read_register(registers::version); + auto version = (raw_version >> offset_of_version) & 0xff; + auto highest_lvt_entry_index = (raw_version >> offset_of_max_lvt_entry) & 0xff; + auto supports_eoi_broadcast_suppression = bool((raw_version >> offset_of_eoi_suppression) & 0x1); + + write_register(registers::spurious_interrupt_vector, lapic_enable_bit | spurious_interrupt_vector); + + kstd::println("[x86_64:DRV] LAPIC initialized. version: {#x} | max_lvt_entry: {} | eoi_suppression: {:s}", + version, highest_lvt_entry_index, supports_eoi_broadcast_suppression); + } + else + { + kstd::println("[x86_64:DRV] LAPIC {} is not on the BSP, deferring initialization.", signature->hardware_id()); + } + + return kstd::success(); + } + + auto lapic::unbind(kapi::devices::device &) -> void {} + + auto lapic::name() const noexcept -> std::string_view + { + return "Generic x86 Local APIC"; + } + + auto lapic::read_register(registers id) const -> std::uint32_t + { + auto reg = static_cast<std::uint32_t volatile *>(m_mapped_region.first + std::to_underlying(id)); + return *reg; + } + + auto lapic::write_register(registers id, std::uint32_t value) -> void + { + auto reg = static_cast<std::uint32_t volatile *>(m_mapped_region.first + std::to_underlying(id)); + *reg = value; + } + + auto lapic::query_facet(kapi::capabilities::facet_id facet) -> void * + { + if (facet == arch::bus::lapic_claim::id) + { + return static_cast<arch::bus::lapic_claim *>(this); + } + + return kapi::devices::driver::query_facet(facet); + } + +} // namespace arch::drivers diff --git a/arch/x86_64/arch/drivers/lapic.hpp b/arch/x86_64/arch/drivers/lapic.hpp new file mode 100644 index 00000000..f9d697f8 --- /dev/null +++ b/arch/x86_64/arch/drivers/lapic.hpp @@ -0,0 +1,45 @@ +#ifndef TEACHOS_ARCH_X86_64_DRIVERS_LAPIC_HPP +#define TEACHOS_ARCH_X86_64_DRIVERS_LAPIC_HPP + +#include <arch/bus/cpu.hpp> + +#include <kapi/capabilities/facet_id.hpp> +#include <kapi/devices.hpp> +#include <kapi/memory.hpp> +#include <kapi/tracked_mutex.hpp> + +#include <kstd/result.hpp> + +#include <cstddef> +#include <cstdint> +#include <string_view> + +namespace arch::drivers +{ + + //! The driver for a core-local interrupt controller (local APIC). + struct lapic final : kapi::devices::driver, arch::bus::lapic_claim + { + [[nodiscard]] auto probe(kapi::devices::device & device) -> kstd::result<void> override; + + auto unbind(kapi::devices::device & device) -> void override; + + [[nodiscard]] auto name() const noexcept -> std::string_view override; + + protected: + auto query_facet(kapi::capabilities::facet_id facet) -> void * override; + + private: + enum struct registers : std::ptrdiff_t; + + [[nodiscard]] auto read_register(registers id) const -> std::uint32_t; + auto write_register(registers id, std::uint32_t value) -> void; + + mutable kapi::tracked_mutex m_lock{}; + kapi::memory::mmio_region m_mapped_region{}; + bool m_is_mapped{}; + }; + +} // namespace arch::drivers + +#endif diff --git a/arch/x86_64/arch/drivers/pit.cpp b/arch/x86_64/arch/drivers/pit.cpp index 94fa19e9..49b3f228 100644 --- a/arch/x86_64/arch/drivers/pit.cpp +++ b/arch/x86_64/arch/drivers/pit.cpp @@ -3,6 +3,7 @@ #include <arch/bus/isa.hpp> #include <arch/io/port_io.hpp> +#include <kapi/capabilities/facet_id.hpp> #include <kapi/devices.hpp> #include <kapi/interrupts.hpp> diff --git a/arch/x86_64/arch/vga/crtc.hpp b/arch/x86_64/arch/vga/crtc.hpp index a8bec937..1a794977 100644 --- a/arch/x86_64/arch/vga/crtc.hpp +++ b/arch/x86_64/arch/vga/crtc.hpp @@ -1,7 +1,7 @@ #ifndef TEACHOS_X86_64_VGA_IO_HPP #define TEACHOS_X86_64_VGA_IO_HPP -#include <arch/device_io/port_io.hpp> +#include <arch/io/port_io.hpp> #include <cstddef> diff --git a/arch/x86_64/kapi/cpu.cpp b/arch/x86_64/kapi/cpu.cpp index 100f53df..2bec841c 100644 --- a/arch/x86_64/kapi/cpu.cpp +++ b/arch/x86_64/kapi/cpu.cpp @@ -1,32 +1,14 @@ #include <kapi/cpu.hpp> #include <arch/cpu/initialization.hpp> -#include <arch/devices/local_apic.hpp> -#include <kapi/acpi.hpp> -#include <kapi/devices.hpp> -#include <kapi/devices/cpu.hpp> -#include <kapi/memory.hpp> #include <kapi/system.hpp> -#include <acpi/acpi.hpp> - -#include <kstd/memory.hpp> -#include <kstd/print.hpp> - #include <atomic> -#include <ranges> -#include <utility> namespace kapi::cpu { - namespace - { - constexpr auto candidate_flags = ::acpi::processor_local_apic_entry::flags::processor_enabled // - | ::acpi::processor_local_apic_entry::flags::online_capable; - } - auto init() -> void { auto static constinit is_initialized = std::atomic_flag{}; @@ -46,42 +28,6 @@ namespace kapi::cpu __builtin_unreachable(); } - auto discover_topology() -> bool - { - auto madt = kapi::acpi::get_table<::acpi::table_signature_v<::acpi::madt>>(); - if (!madt) - { - kstd::println("[x86_64:PLT] Failed to find ACPI APIC table"); - return false; - } - - auto lapic_entries = *madt | std::views::filter([](auto const & entry) { - return entry.type() == ::acpi::madt_entry::type::processor_local_apic; - }) | std::views::transform([](auto const & entry) { - return static_cast<::acpi::processor_local_apic_entry const &>(entry); - }) | std::views::filter([](auto const & entry) { return static_cast<bool>(entry.flags() & candidate_flags); }); - - auto bsp_found = false; - auto core_index = 0uz; - auto local_apic_address = memory::physical_address{madt->local_interrupt_controller_address()}; - auto cpu_bus = kstd::make_shared<devices::cpu>(); - - for (auto const & apic : lapic_entries) - { - auto is_bsp = !bsp_found; - bsp_found = true; - auto core = kstd::make_shared<devices::cpu::core>(core_index, apic.processor_id(), is_bsp); - core->add_child(kstd::make_shared<arch::devices::local_apic>(core_index, apic.id(), local_apic_address, is_bsp)); - cpu_bus->add_child(std::move(core)); - ++core_index; - } - - devices::get_root_bus()->add_child(std::move(cpu_bus)); - - kstd::println("[x86_64:PLT] Found {} CPU cores", core_index); - return core_index > 0; - } - auto current_id() -> id { // TODO: implement actual ID reading once APs are being set up. diff --git a/arch/x86_64/kapi/devices.cpp b/arch/x86_64/kapi/devices.cpp index 748e0a6a..04b6fa2d 100644 --- a/arch/x86_64/kapi/devices.cpp +++ b/arch/x86_64/kapi/devices.cpp @@ -1,11 +1,21 @@ #include <kapi/devices.hpp> +#include <arch/bus/cpu.hpp> #include <arch/devices/init.hpp> #include <arch/drivers/init.hpp> +#include <kapi/system.hpp> + +#include <kstd/memory.hpp> + namespace kapi::devices { + namespace + { + auto static constinit cpu_bus = kstd::shared_ptr<arch::bus::cpu>{}; + } + auto init_platform_drivers() -> void { arch::drivers::init_legacy_drivers(); @@ -17,4 +27,25 @@ namespace kapi::devices arch::devices::init_legacy_devices(); } + auto get_cpu_bus() -> kstd::shared_ptr<bus> + { + if (!cpu_bus) + { + system::panic("[x86_64:DEV] The CPU topology has not yet been initialized!"); + } + + return cpu_bus; + } + + auto discover_cpu_topology() -> void + { + if (cpu_bus) + { + system::panic("[x86_64:DEV] The CPU topology has already been initialized!"); + } + + cpu_bus = kstd::make_shared<arch::bus::cpu>(); + cpu_bus->facet<kapi::devices::bus_protocol>()->enumerate(*cpu_bus); + } + } // namespace kapi::devices
\ No newline at end of file diff --git a/kapi/kapi/cpu.hpp b/kapi/kapi/cpu.hpp index 9a50f67e..7337a45a 100644 --- a/kapi/kapi/cpu.hpp +++ b/kapi/kapi/cpu.hpp @@ -101,11 +101,6 @@ namespace kapi::cpu //! interrupts itself. auto init() -> void; - //! Discover the CPU topology of the platform and attach it to the given CPU bus. - //! - //! @return true iff. the CPU topology was discovered successfully, false otherwise. - auto discover_topology() -> bool; - //! Get the current CPU id. //! //! @return The id of the CPU core currently executing the call to this function. diff --git a/kapi/kapi/devices.hpp b/kapi/kapi/devices.hpp index 8c0c238e..b20e3546 100644 --- a/kapi/kapi/devices.hpp +++ b/kapi/kapi/devices.hpp @@ -1,10 +1,8 @@ #ifndef TEACHOS_KAPI_DEVICES_HPP #define TEACHOS_KAPI_DEVICES_HPP -#include <kapi/capabilities/facet_id.hpp> // IWYU pragma: export #include <kapi/devices/bus.hpp> // IWYU pragma: export #include <kapi/devices/bus_protocol.hpp> // IWYU pragma: export -#include <kapi/devices/cpu.hpp> // IWYU pragma: export #include <kapi/devices/device.hpp> // IWYU pragma: export #include <kapi/devices/device_registry.hpp> // IWYU pragma: export #include <kapi/devices/driver.hpp> // IWYU pragma: export @@ -75,6 +73,16 @@ namespace kapi::devices //! Initialize the platform's device tree. auto init_platform_devices() -> void; + //! Discover the platform's CPU topology + auto discover_cpu_topology() -> void; + + //! Get the virtual system CPU bus. + //! + //! @warning This function will panic if the CPU topology has not been discovered. + //! + //! @return a shared pointer to the CPU bus. + auto get_cpu_bus() -> kstd::shared_ptr<bus>; + //! @} } // namespace kapi::devices diff --git a/kapi/kapi/devices/cpu.hpp b/kapi/kapi/devices/cpu.hpp deleted file mode 100644 index 708c803e..00000000 --- a/kapi/kapi/devices/cpu.hpp +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef TEACHOS_KAPI_DEVICES_CPU_HPP -#define TEACHOS_KAPI_DEVICES_CPU_HPP - -#include <kapi/devices/bus.hpp> - -#include <cstdint> - -namespace kapi::devices -{ - - //! A virtual CPU bus to host all CPUs in the system. - struct cpu final : kapi::devices::bus - { - //! A virtual CPU Core to host all core local devices. - struct core final : kapi::devices::bus - { - core(std::uint64_t index, std::uint64_t hardware_id, bool is_bsp); - - [[nodiscard]] auto hardware_id() const -> std::uint64_t; - [[nodiscard]] auto is_bsp() const -> bool; - [[nodiscard]] auto index() const noexcept -> std::uint64_t; - - private: - std::uint64_t m_index; - std::uint64_t m_hardware_id; - bool m_is_bsp; - }; - - //! Create a new CPU. - cpu(); - }; - -} // namespace kapi::devices - -#endif
\ No newline at end of file diff --git a/kernel/CMakeLists.txt b/kernel/CMakeLists.txt index 7bae7b07..91075adc 100644 --- a/kernel/CMakeLists.txt +++ b/kernel/CMakeLists.txt @@ -13,7 +13,6 @@ target_sources("kernel_lib" PRIVATE "kapi/cpu.cpp" "kapi/devices.cpp" "kapi/devices/bus.cpp" - "kapi/devices/cpu.cpp" "kapi/devices/device.cpp" "kapi/devices/device_registry.cpp" "kapi/devices/driver.cpp" diff --git a/kernel/kapi/boot_modules/device.cpp b/kernel/kapi/boot_modules/device.cpp index b9262abf..d60cc406 100644 --- a/kernel/kapi/boot_modules/device.cpp +++ b/kernel/kapi/boot_modules/device.cpp @@ -1,6 +1,7 @@ #include <kapi/boot_modules/device.hpp> #include <kapi/boot_modules/module.hpp> +#include <kapi/capabilities/facet_id.hpp> #include <kapi/devices.hpp> #include <kstd/format.hpp> diff --git a/kernel/kapi/devices/bus.cpp b/kernel/kapi/devices/bus.cpp index 1398c781..e4b5a2c5 100644 --- a/kernel/kapi/devices/bus.cpp +++ b/kernel/kapi/devices/bus.cpp @@ -1,5 +1,6 @@ #include <kapi/devices/bus.hpp> +#include <kapi/capabilities/facet_id.hpp> #include <kapi/devices.hpp> #include <kapi/devices/bus_protocol.hpp> #include <kapi/devices/driver_registry.hpp> diff --git a/kernel/kapi/devices/cpu.cpp b/kernel/kapi/devices/cpu.cpp deleted file mode 100644 index daba34a8..00000000 --- a/kernel/kapi/devices/cpu.cpp +++ /dev/null @@ -1,38 +0,0 @@ -#include <kapi/devices/cpu.hpp> - -#include <kapi/devices.hpp> - -#include <kstd/format.hpp> - -#include <cstdint> - -namespace kapi::devices -{ - - cpu::core::core(std::uint64_t index, std::uint64_t hardware_id, bool is_bsp) - : kapi::devices::bus{kstd::format("cpu_core{}", index)} - , m_index{index} - , m_hardware_id{hardware_id} - , m_is_bsp{is_bsp} - {} - - auto cpu::core::index() const noexcept -> std::uint64_t - { - return m_index; - } - - 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() - : kapi::devices::bus{"cpu"} - {} - -} // namespace kapi::devices
\ No newline at end of file diff --git a/kernel/kapi/devices/device.cpp b/kernel/kapi/devices/device.cpp index 6f05954a..2576e20a 100644 --- a/kernel/kapi/devices/device.cpp +++ b/kernel/kapi/devices/device.cpp @@ -1,5 +1,6 @@ #include <kapi/devices/device.hpp> +#include <kapi/capabilities/facet_id.hpp> #include <kapi/devices.hpp> #include <kapi/devices/bus.hpp> #include <kapi/devices/resource.hpp> diff --git a/kernel/kapi/devices/driver.cpp b/kernel/kapi/devices/driver.cpp index 55b7507b..ee16b4c2 100644 --- a/kernel/kapi/devices/driver.cpp +++ b/kernel/kapi/devices/driver.cpp @@ -1,3 +1,4 @@ +#include <kapi/capabilities/facet_id.hpp> #include <kapi/devices.hpp> #include <cstdint> diff --git a/kernel/kapi/devices/facet_registry.cpp b/kernel/kapi/devices/facet_registry.cpp index 623ecba2..b2d12c86 100644 --- a/kernel/kapi/devices/facet_registry.cpp +++ b/kernel/kapi/devices/facet_registry.cpp @@ -1,5 +1,6 @@ #include <kapi/devices/facet_registry.hpp> +#include <kapi/capabilities/facet_id.hpp> #include <kapi/devices.hpp> #include <kapi/system.hpp> #include <kapi/test_support/devices.hpp> |
