From 3dcd14a0570fef3bcc68d7df42fe3ff4cd496f93 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Mon, 6 Apr 2026 14:47:37 +0200 Subject: kapi: hook ACPI initialization up to boot process --- .vscode/settings.json | 6 +++- arch/x86_64/kapi/devices.cpp | 32 +++++++++++++++++++- kapi/include/kapi/acpi.hpp | 44 +++++++++++++++++++-------- kapi/include/kapi/memory/layout.hpp | 12 ++++++++ kernel/CMakeLists.txt | 1 + kernel/include/kernel/acpi/manager.hpp | 26 ++++++++++++++++ kernel/kapi/acpi.cpp | 32 ++++++++++++++++---- kernel/src/acpi/manager.cpp | 54 ++++++++++++++++++++++++++++++++++ 8 files changed, 186 insertions(+), 21 deletions(-) create mode 100644 kernel/include/kernel/acpi/manager.hpp create mode 100644 kernel/src/acpi/manager.cpp diff --git a/.vscode/settings.json b/.vscode/settings.json index 4271526..6ea3c79 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -32,6 +32,7 @@ "crtp", "efer", "functors", + "hhdm", "idtr", "initializable", "interprocedural", @@ -43,6 +44,7 @@ "malloc", "memcmp", "memset", + "mmio", "multiboot", "nodiscard", "nolintnextline", @@ -51,12 +53,14 @@ "raii", "rdmsr", "RSDP", + "rsdt", "rvalues", "stringview", "sysret", "teachos", "undelegated", - "wrmsr" + "wrmsr", + "xsdp" ], "testMate.cpp.debug.configTemplate": { "type": "cppdbg", diff --git a/arch/x86_64/kapi/devices.cpp b/arch/x86_64/kapi/devices.cpp index b15503d..e1773e7 100644 --- a/arch/x86_64/kapi/devices.cpp +++ b/arch/x86_64/kapi/devices.cpp @@ -1,5 +1,9 @@ #include "kapi/devices.hpp" +#include "kapi/acpi.hpp" +#include "kapi/boot.hpp" + +#include "arch/boot/boot.hpp" #include "arch/bus/isa.hpp" #include "arch/devices/legacy_pit.hpp" @@ -19,7 +23,33 @@ namespace kapi::devices auto init_platform_devices() -> void { - kstd::println("[x86_64:devices] Initializing ISA bus..."); + auto const & mbi = boot::bootstrap_information.mbi; + auto system_description_pointer = static_cast(nullptr); + + if (auto const & xsdp = mbi->maybe_acpi_xsdp()) + { + auto data = xsdp->pointer().data(); + system_description_pointer = reinterpret_cast(data); + } + else if (auto const & rsdp = mbi->maybe_acpi_rsdp()) + { + auto data = rsdp->pointer().data(); + system_description_pointer = reinterpret_cast(data); + } + + if (system_description_pointer) + { + if (!kapi::acpi::init(*system_description_pointer)) + { + kstd::println(kstd::print_sink::stderr, "[x86_64:DEV] ACPI initialization failed. No tables loaded."); + } + } + else + { + kstd::println(kstd::print_sink::stderr, "[x86_64:DEV] No ACPI RSDP found. Most devices will not be available."); + } + + kstd::println("[x86_64:DEV] Initializing ISA bus..."); auto isa_major_number = kapi::devices::allocate_major_number(); auto isa_bus = kstd::make_unique(isa_major_number); diff --git a/kapi/include/kapi/acpi.hpp b/kapi/include/kapi/acpi.hpp index 1068921..d5e3c87 100644 --- a/kapi/include/kapi/acpi.hpp +++ b/kapi/include/kapi/acpi.hpp @@ -2,16 +2,36 @@ #define TEACHOS_KAPI_ACPI_HPP #include "kapi/memory.hpp" + #include #include #include #include +#include #include namespace kapi::acpi { + //! @addtogroup kapi-acpi + //! @{ + + struct [[gnu::packed]] system_description_table_header + { + std::array signature; + std::uint32_t length; + std::uint8_t revision; + std::uint8_t checksum; + std::array oem_id; + std::array oem_table_id; + std::uint32_t oem_revision; + std::uint32_t creator_id; + std::uint32_t create_revision; + }; + + //! @} + //! @addtogroup kapi-acpi-kernel-defined //! @{ @@ -44,20 +64,18 @@ namespace kapi::acpi [[maybe_unused]] std::array m_reserved; }; - //! @} + //! Initialize the ACPI subsystem and discover the available tables. + //! + //! @return true iff. a valid system description tabled was found, false otherwise. + auto init(root_system_description_pointer const & sdp) -> bool; - struct [[gnu::packed]] system_description_table_header - { - std::array signature; - std::uint32_t length; - std::uint8_t revision; - std::uint8_t checksum; - std::array oem_id; - std::array oem_table_id; - std::uint32_t oem_revision; - std::uint32_t creator_id; - std::uint32_t create_revision; - }; + //! Validate and ACPI entity checksum. + //! + //! @param data The data to validate the checksum of. + //! @return true iff. the checksum is valid, false otherwise. + auto validate_checksum(std::span data) -> bool; + + //! @} } // namespace kapi::acpi diff --git a/kapi/include/kapi/memory/layout.hpp b/kapi/include/kapi/memory/layout.hpp index 157f41e..26b48d8 100644 --- a/kapi/include/kapi/memory/layout.hpp +++ b/kapi/include/kapi/memory/layout.hpp @@ -37,6 +37,18 @@ namespace kapi::memory //! The linear base address of the loaded kernel image. constexpr auto kernel_base = linear_address{0xffff'ffff'8000'0000uz}; + //! Convert a physical address to a linear address using the higher-half direct map. + constexpr auto hhdm_to_linear(physical_address address) -> linear_address + { + return linear_address{address.raw() + higher_half_direct_map_base.raw()}; + } + + //! Convert a linear address in the higher-half direct map to a physical address. + constexpr auto hhdm_to_physical(linear_address address) -> physical_address + { + return physical_address{address.raw() - higher_half_direct_map_base.raw()}; + } + } // namespace kapi::memory #endif \ No newline at end of file diff --git a/kernel/CMakeLists.txt b/kernel/CMakeLists.txt index ab77467..fc01723 100644 --- a/kernel/CMakeLists.txt +++ b/kernel/CMakeLists.txt @@ -14,6 +14,7 @@ add_library("kernel_objs" OBJECT "kstd/print.cpp" # Kernel Implementation + "src/acpi/manager.cpp" "src/memory/bitmap_allocator.cpp" "src/memory/block_list_allocator.cpp" "src/memory.cpp" diff --git a/kernel/include/kernel/acpi/manager.hpp b/kernel/include/kernel/acpi/manager.hpp new file mode 100644 index 0000000..fc76685 --- /dev/null +++ b/kernel/include/kernel/acpi/manager.hpp @@ -0,0 +1,26 @@ +#ifndef TEACHOS_KERNEL_ACPI_MANAGER_HPP +#define TEACHOS_KERNEL_ACPI_MANAGER_HPP + +#include "kapi/acpi.hpp" + +#include + +namespace kernel::acpi +{ + + struct manager + { + explicit manager(kapi::acpi::root_system_description_pointer const & sdp); + + auto load_tables() -> bool; + + private: + kapi::acpi::root_system_description_pointer const * m_sdp{}; + kapi::acpi::system_description_table_header const * m_rsdt{}; + kstd::vector m_tables{}; + bool m_extended{}; + }; + +} // namespace kernel::acpi + +#endif diff --git a/kernel/kapi/acpi.cpp b/kernel/kapi/acpi.cpp index aa0066d..787bcff 100644 --- a/kernel/kapi/acpi.cpp +++ b/kernel/kapi/acpi.cpp @@ -1,13 +1,18 @@ #include "kapi/acpi.hpp" #include "kapi/memory.hpp" +#include "kapi/system.hpp" + +#include "kernel/acpi/manager.hpp" #include #include +#include #include #include #include +#include #include #include @@ -16,12 +21,7 @@ namespace kapi::acpi namespace { - constexpr auto validate_checksum(std::span data) -> bool - { - auto sum = std::ranges::fold_left( - data, std::uint8_t{}, [](std::uint8_t acc, auto byte) { return static_cast(byte) + acc; }); - return sum == 0; - } + auto constinit manager = std::optional{}; } // namespace auto root_system_description_pointer::oem_id() const noexcept -> std::string_view @@ -65,4 +65,24 @@ namespace kapi::acpi return validate_checksum({reinterpret_cast(this), m_length}); } + auto init(root_system_description_pointer const & sdp) -> bool + { + auto static constinit initialized = std::atomic_flag{}; + if (initialized.test_and_set()) + { + system::panic("[OS::ACPI] The ACPI manager has already been initialized!"); + } + + manager.emplace(sdp); + return manager->load_tables(); + } + + auto validate_checksum(std::span data) -> bool + { + auto sum = std::ranges::fold_left(data, std::uint8_t{}, [](auto acc, auto byte) { + return static_cast(acc + static_cast(byte)); + }); + return sum == 0; + } + }; // namespace kapi::acpi diff --git a/kernel/src/acpi/manager.cpp b/kernel/src/acpi/manager.cpp new file mode 100644 index 0000000..6a17920 --- /dev/null +++ b/kernel/src/acpi/manager.cpp @@ -0,0 +1,54 @@ +#include "kernel/acpi/manager.hpp" + +#include "kapi/acpi.hpp" +#include "kapi/memory.hpp" +#include "kapi/system.hpp" + +#include + +namespace kernel::acpi +{ + + manager::manager(kapi::acpi::root_system_description_pointer const & sdp) + : m_sdp{&sdp} + { + if (m_sdp->signature() != "RSD PTR ") + { + kapi::system::panic("[OS:ACPI] Invalid RSDP signature!"); + } + + if (m_sdp->revision() >= 2) + { + auto const xsdp = static_cast(m_sdp); + if (!xsdp->validate()) + { + kapi::system::panic("[OS:ACPI] Invalid XSDP signature!"); + } + auto physical_extended_table_address = xsdp->table_address(); + auto linear_extended_table_address = kapi::memory::hhdm_to_linear(physical_extended_table_address); + m_rsdt = static_cast(linear_extended_table_address); + m_extended = true; + } + else + { + if (!m_sdp->validate()) + { + kapi::system::panic("[OS:ACPI] Invalid RSDP checksum!"); + } + auto physical_root_table_address = m_sdp->table_address(); + auto linear_root_table_address = kapi::memory::hhdm_to_linear(physical_root_table_address); + m_rsdt = static_cast(linear_root_table_address); + } + } + + auto manager::load_tables() -> bool + { + if (!kapi::acpi::validate_checksum({reinterpret_cast(m_rsdt), m_rsdt->length})) + { + kapi::system::panic("[OS:ACPI] Invalid RSDT checksum!"); + } + + return false; + } + +} // namespace kernel::acpi -- cgit v1.2.3