aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFelix Morgner <felix.morgner@ost.ch>2026-07-28 13:09:08 +0200
committerFelix Morgner <felix.morgner@ost.ch>2026-07-28 13:09:08 +0200
commit36248bb63a396dfea762d5b2cf028bf4b7a2b62e (patch)
treeb05726555a387b719292a4d19c4c4a5cbc7e31cc
parentb5450cecbffdca1dd9dffdb58dd295a6a5d7f6eb (diff)
downloadkernel-36248bb63a396dfea762d5b2cf028bf4b7a2b62e.tar.xz
kernel-36248bb63a396dfea762d5b2cf028bf4b7a2b62e.zip
x86_64: split lapic according to UDM
-rw-r--r--arch/x86_64/CMakeLists.txt5
-rw-r--r--arch/x86_64/arch/bus/cpu.cpp109
-rw-r--r--arch/x86_64/arch/bus/cpu.hpp76
-rw-r--r--arch/x86_64/arch/cpu/legacy_pic.hpp2
-rw-r--r--arch/x86_64/arch/devices/cpu/core.cpp42
-rw-r--r--arch/x86_64/arch/devices/cpu/core.hpp34
-rw-r--r--arch/x86_64/arch/devices/cpu/lapic.cpp42
-rw-r--r--arch/x86_64/arch/devices/cpu/lapic.hpp32
-rw-r--r--arch/x86_64/arch/devices/init.cpp3
-rw-r--r--arch/x86_64/arch/devices/local_apic.cpp136
-rw-r--r--arch/x86_64/arch/devices/local_apic.hpp37
-rw-r--r--arch/x86_64/arch/devices/pit.cpp1
-rw-r--r--arch/x86_64/arch/drivers/init.cpp2
-rw-r--r--arch/x86_64/arch/drivers/lapic.cpp167
-rw-r--r--arch/x86_64/arch/drivers/lapic.hpp45
-rw-r--r--arch/x86_64/arch/drivers/pit.cpp1
-rw-r--r--arch/x86_64/arch/vga/crtc.hpp2
-rw-r--r--arch/x86_64/kapi/cpu.cpp54
-rw-r--r--arch/x86_64/kapi/devices.cpp31
-rw-r--r--kapi/kapi/cpu.hpp5
-rw-r--r--kapi/kapi/devices.hpp12
-rw-r--r--kapi/kapi/devices/cpu.hpp35
-rw-r--r--kernel/CMakeLists.txt1
-rw-r--r--kernel/kapi/boot_modules/device.cpp1
-rw-r--r--kernel/kapi/devices/bus.cpp1
-rw-r--r--kernel/kapi/devices/cpu.cpp38
-rw-r--r--kernel/kapi/devices/device.cpp1
-rw-r--r--kernel/kapi/devices/driver.cpp1
-rw-r--r--kernel/kapi/devices/facet_registry.cpp1
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>