From c3f7b747f02a79b34ed914c54ce74be973b17af1 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Fri, 10 Apr 2026 17:39:14 +0200 Subject: kapi: extract ACPI functionality to libs --- arch/x86_64/kapi/acpi.cpp | 10 +- arch/x86_64/kapi/cpu.cpp | 15 +-- kapi/CMakeLists.txt | 1 + kapi/include/kapi/acpi.hpp | 25 ++--- .../kapi/acpi/multiple_apic_description_table.hpp | 104 ------------------ kapi/include/kapi/acpi/pointers.hpp | 79 -------------- .../kapi/acpi/system_description_table_header.hpp | 76 ------------- kapi/include/kapi/acpi/table_iterator.hpp | 64 ----------- kapi/include/kapi/acpi/table_type.hpp | 22 ---- kernel/CMakeLists.txt | 3 - kernel/include/kernel/acpi/manager.hpp | 14 +-- kernel/kapi/acpi.cpp | 18 +--- .../kapi/acpi/multiple_apic_description_table.cpp | 70 ------------ kernel/kapi/acpi/pointers.cpp | 55 ---------- .../kapi/acpi/system_description_table_header.cpp | 51 --------- kernel/src/acpi/manager.cpp | 29 +++-- libs/CMakeLists.txt | 3 +- libs/acpi/CMakeLists.txt | 29 +++++ libs/acpi/acpi/acpi.hpp | 10 ++ libs/acpi/acpi/checksum.cpp | 19 ++++ libs/acpi/acpi/checksum.hpp | 20 ++++ libs/acpi/acpi/madt.cpp | 68 ++++++++++++ libs/acpi/acpi/madt.hpp | 92 ++++++++++++++++ libs/acpi/acpi/pointers.cpp | 55 ++++++++++ libs/acpi/acpi/pointers.hpp | 72 +++++++++++++ libs/acpi/acpi/sdt.cpp | 51 +++++++++ libs/acpi/acpi/sdt.hpp | 119 +++++++++++++++++++++ libs/acpi/acpi/table_type.hpp | 17 +++ 28 files changed, 602 insertions(+), 589 deletions(-) delete mode 100644 kapi/include/kapi/acpi/multiple_apic_description_table.hpp delete mode 100644 kapi/include/kapi/acpi/pointers.hpp delete mode 100644 kapi/include/kapi/acpi/system_description_table_header.hpp delete mode 100644 kapi/include/kapi/acpi/table_iterator.hpp delete mode 100644 kapi/include/kapi/acpi/table_type.hpp delete mode 100644 kernel/kapi/acpi/multiple_apic_description_table.cpp delete mode 100644 kernel/kapi/acpi/pointers.cpp delete mode 100644 kernel/kapi/acpi/system_description_table_header.cpp create mode 100644 libs/acpi/CMakeLists.txt create mode 100644 libs/acpi/acpi/acpi.hpp create mode 100644 libs/acpi/acpi/checksum.cpp create mode 100644 libs/acpi/acpi/checksum.hpp create mode 100644 libs/acpi/acpi/madt.cpp create mode 100644 libs/acpi/acpi/madt.hpp create mode 100644 libs/acpi/acpi/pointers.cpp create mode 100644 libs/acpi/acpi/pointers.hpp create mode 100644 libs/acpi/acpi/sdt.cpp create mode 100644 libs/acpi/acpi/sdt.hpp create mode 100644 libs/acpi/acpi/table_type.hpp diff --git a/arch/x86_64/kapi/acpi.cpp b/arch/x86_64/kapi/acpi.cpp index ec38aee..40b7160 100644 --- a/arch/x86_64/kapi/acpi.cpp +++ b/arch/x86_64/kapi/acpi.cpp @@ -4,24 +4,26 @@ #include +#include + namespace kapi::acpi { - auto get_root_pointer() -> kstd::observer_ptr + auto get_root_pointer() -> kstd::observer_ptr<::acpi::rsdp const> { auto const & mbi = kapi::boot::bootstrap_information.mbi; - auto system_description_pointer = static_cast(nullptr); + auto system_description_pointer = static_cast<::acpi::rsdp const *>(nullptr); if (auto const & xsdp = mbi->maybe_acpi_xsdp()) { auto data = xsdp->pointer().data(); - system_description_pointer = reinterpret_cast(data); + system_description_pointer = reinterpret_cast<::acpi::xsdp const *>(data); } else if (auto const & rsdp = mbi->maybe_acpi_rsdp()) { auto data = rsdp->pointer().data(); - system_description_pointer = reinterpret_cast(data); + system_description_pointer = reinterpret_cast<::acpi::rsdp const *>(data); } return kstd::make_observer(system_description_pointer); diff --git a/arch/x86_64/kapi/cpu.cpp b/arch/x86_64/kapi/cpu.cpp index 726ec6a..a836b20 100644 --- a/arch/x86_64/kapi/cpu.cpp +++ b/arch/x86_64/kapi/cpu.cpp @@ -3,6 +3,7 @@ #include "kapi/acpi.hpp" #include "kapi/devices.hpp" #include "kapi/devices/cpu.hpp" +#include "kapi/memory.hpp" #include "kapi/system.hpp" #include "arch/cpu/initialization.hpp" @@ -11,6 +12,8 @@ #include #include +#include + #include #include #include @@ -20,8 +23,8 @@ namespace kapi::cpu namespace { - constexpr auto candidate_flags = acpi::processor_local_apic::flags::processor_enabled // - | acpi::processor_local_apic::flags::online_capable; + constexpr auto candidate_flags = ::acpi::processor_local_apic::flags::processor_enabled // + | ::acpi::processor_local_apic::flags::online_capable; } auto init() -> void @@ -49,7 +52,7 @@ namespace kapi::cpu auto static const core_major = kapi::devices::allocate_major_number(); auto static const interrupt_controller_major = kapi::devices::allocate_major_number(); - auto madt = kapi::acpi::get_table(); + auto madt = kapi::acpi::get_table<::acpi::madt_table_signature>(); if (!madt) { kstd::println("[x86_64:PLT] Failed to find ACPI APIC table"); @@ -57,16 +60,16 @@ namespace kapi::cpu } auto lapic_entries = *madt | std::views::filter([](auto const & entry) { - return entry.type() == acpi::multiple_apic_description_table_entry::types::processor_local_apic; + return entry.type() == ::acpi::madt_entry::types::processor_local_apic; }) | std::views::transform([](auto const & entry) { - return static_cast(entry); + return static_cast<::acpi::processor_local_apic const &>(entry); }) | std::views::filter([](auto const & entry) { return static_cast(entry.active_flags() & candidate_flags); }); auto bsp_found = false; auto core_count = 0uz; - auto local_apic_address = madt->local_interrupt_controller_address(); + auto local_apic_address = memory::physical_address{madt->local_interrupt_controller_address()}; auto cpu_bus = kstd::make_unique(cpu_major, 0); for (auto const & apic : lapic_entries) diff --git a/kapi/CMakeLists.txt b/kapi/CMakeLists.txt index c9aa23f..99a8725 100644 --- a/kapi/CMakeLists.txt +++ b/kapi/CMakeLists.txt @@ -15,6 +15,7 @@ target_include_directories("kapi" INTERFACE ) target_link_libraries("kapi" INTERFACE + "libs::acpi" "libs::kstd" "gcc" diff --git a/kapi/include/kapi/acpi.hpp b/kapi/include/kapi/acpi.hpp index 5323fee..01fd113 100644 --- a/kapi/include/kapi/acpi.hpp +++ b/kapi/include/kapi/acpi.hpp @@ -1,16 +1,11 @@ #ifndef TEACHOS_KAPI_ACPI_HPP #define TEACHOS_KAPI_ACPI_HPP -#include "kapi/acpi/multiple_apic_description_table.hpp" // IWYU pragma: export -#include "kapi/acpi/pointers.hpp" // IWYU pragma: export -#include "kapi/acpi/system_description_table_header.hpp" // IWYU pragma: export -#include "kapi/acpi/table_type.hpp" - #include #include -#include -#include +#include + #include namespace kapi::acpi @@ -22,28 +17,22 @@ namespace kapi::acpi //! 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; - - //! 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; + auto init(::acpi::rsdp const & sdp) -> bool; //! Get a pointer to an ACPI table by its signature. //! //! @param signature The signature of the table to get. //! @return A pointer to the table if found, nullptr otherwise. - auto get_table(std::string_view signature) -> kstd::observer_ptr; + auto get_table(std::string_view signature) -> kstd::observer_ptr<::acpi::sdt const>; //! Get a type-cast pointer to an ACPI table by its signature. //! //! @tparam Signature The signature of the table to get //! @return A pointer to the table if found, nullptr otherwise. template - auto get_table() -> kstd::observer_ptr const> + auto get_table() -> kstd::observer_ptr<::acpi::table_type_t const> { - return kstd::make_observer(static_cast const *>(get_table(Signature).get())); + return kstd::make_observer(static_cast<::acpi::table_type_t const *>(get_table(Signature).get())); } //! @} @@ -54,7 +43,7 @@ namespace kapi::acpi //! Retrieve the RSDP or XSDP for this system. //! //! @return a pointer to either the RSDP or XSDP data structure, or @p nullptr if neither is present. - auto get_root_pointer() -> kstd::observer_ptr; + auto get_root_pointer() -> kstd::observer_ptr<::acpi::rsdp const>; //! @} diff --git a/kapi/include/kapi/acpi/multiple_apic_description_table.hpp b/kapi/include/kapi/acpi/multiple_apic_description_table.hpp deleted file mode 100644 index 33acac9..0000000 --- a/kapi/include/kapi/acpi/multiple_apic_description_table.hpp +++ /dev/null @@ -1,104 +0,0 @@ -#ifndef TEACHOS_KAPI_ACPI_MUTIPLE_APIC_DESCRIPTION_TABLE_HEADER_HPP -#define TEACHOS_KAPI_ACPI_MUTIPLE_APIC_DESCRIPTION_TABLE_HEADER_HPP - -// IWYU pragma: private, include "kapi/acpi.hpp" - -#include "kapi/acpi/system_description_table_header.hpp" -#include "kapi/acpi/table_iterator.hpp" -#include "kapi/acpi/table_type.hpp" -#include "kapi/memory.hpp" - -#include -#include - -#include -#include -#include - -namespace kapi::acpi -{ - - //! @addtogroup kapi-acpi-kernel-defined - //! @{ - - struct [[gnu::packed]] multiple_apic_description_table_entry - { - enum struct types : std::uint8_t - { - processor_local_apic, - io_apic, - io_apic_interrupt_source_override, - io_apic_nmi_source, - local_apic_nmi_interrupts, - local_apic_address_override, - processor_local_x2_apic, - }; - - [[nodiscard]] auto type() const noexcept -> types; - [[nodiscard]] auto length() const noexcept -> std::size_t; - - private: - std::uint8_t m_type; - std::uint8_t m_length; - }; - - //! The common header for all - struct [[gnu::packed]] multiple_apic_description_table : system_description_table_header - { - using iterator = table_iterator; - using const_iterator = iterator; - - [[nodiscard]] auto local_interrupt_controller_address() const noexcept -> memory::physical_address; - [[nodiscard]] auto flags() const noexcept -> std::uint32_t; - - [[nodiscard]] auto begin() const noexcept -> iterator; - [[nodiscard]] auto cbegin() const noexcept -> iterator; - [[nodiscard]] auto end() const noexcept -> iterator; - [[nodiscard]] auto cend() const noexcept -> iterator; - - private: - std::uint32_t m_local_interrupt_controller_address; - std::uint32_t m_flags; - }; - - struct [[gnu::packed]] processor_local_apic : multiple_apic_description_table_entry - { - enum struct flags : std::uint32_t - { - processor_enabled = 1, - online_capable = 2, - }; - - [[nodiscard]] auto apic_id() const noexcept -> std::uint8_t; - [[nodiscard]] auto active_flags() const noexcept -> flags; - [[nodiscard]] auto processor_id() const noexcept -> std::uint32_t; - - private: - std::uint8_t m_processor_id; - std::uint8_t m_apic_id; - std::uint32_t m_flags; - }; - - //! @} - - //! @addtogroup kapi-acpi - //! @{ - - constexpr char const madt_table_signature[] = "APIC"; // NOLINT - - template<> - struct table_type - { - using type = multiple_apic_description_table; - }; - - //! @} - -} // namespace kapi::acpi - -template<> -struct kstd::ext::is_bitfield_enum : std::true_type -{ -}; - -#endif diff --git a/kapi/include/kapi/acpi/pointers.hpp b/kapi/include/kapi/acpi/pointers.hpp deleted file mode 100644 index 2b88720..0000000 --- a/kapi/include/kapi/acpi/pointers.hpp +++ /dev/null @@ -1,79 +0,0 @@ -#ifndef TEACHOS_KAPI_ACPI_POINTERS_HPP -#define TEACHOS_KAPI_ACPI_POINTERS_HPP - -// IWYU pragma: private, include "kapi/acpi.hpp" - -#include "kapi/memory.hpp" - -#include - -#include -#include -#include -#include - -namespace kapi::acpi -{ - - //! @addtogroup kapi-acpi-kernel-defined - //! @{ - - //! A pointer to the Root System Description Table. - struct [[gnu::packed]] root_system_description_pointer - { - //! Get the ID of the OEM, usually a vendor name. - [[nodiscard]] auto oem_id() const noexcept -> std::string_view; - - //! Get the revision of the ACPI Root System Description Table. - //! - //! @note Revisions greater or equal to two indicate that the system uses the Extended System Description Table, and - //! as such that table should be use to query information. - [[nodiscard]] auto revision() const noexcept -> std::uint8_t; - - //! Get the signature of this pointer. - //! - //! A valid RSDP must always carry the signature "RSD PTR ". - [[nodiscard]] auto signature() const noexcept -> std::string_view; - - //! Get the physical address of the pointed-to Root System Description Table. - [[nodiscard]] auto table_address() const noexcept -> memory::physical_address; - - //! Validate the checksum of this RSDP. - //! - //! @return @p true iff. the checksum of this RSDP is valid, @p false otherwise. - [[nodiscard]] auto validate() const noexcept -> bool; - - private: - std::array m_signature; - [[maybe_unused]] std::uint8_t m_checksum; - std::array m_oem_id; - std::uint8_t m_revision; - std::array m_rsdt_address; - }; - - //! A pointer to the Extended System Description Table. - struct [[gnu::packed]] extended_system_description_pointer : root_system_description_pointer - { - //! Get the length of the data contained in this pointer. - [[nodiscard]] auto length() const noexcept -> kstd::units::bytes; - - //! Get the address of the pointed-to Extended System Description Table. - [[nodiscard]] auto table_address() const noexcept -> memory::physical_address; - - //! Validate the checksum of this XSDP. - //! - //! @return @p true iff. the checksum of this RSDP is valid, @p false otherwise. - [[nodiscard]] auto validate() const noexcept -> bool; - - private: - std::uint32_t m_length; - std::array m_xsdt_address; - [[maybe_unused]] std::uint8_t m_extended_checksum; - [[maybe_unused]] std::array m_reserved; - }; - - //! @} - -} // namespace kapi::acpi - -#endif diff --git a/kapi/include/kapi/acpi/system_description_table_header.hpp b/kapi/include/kapi/acpi/system_description_table_header.hpp deleted file mode 100644 index b336ea1..0000000 --- a/kapi/include/kapi/acpi/system_description_table_header.hpp +++ /dev/null @@ -1,76 +0,0 @@ -#ifndef TEACHOS_KAPI_ACPI_SYSTEM_DESCRIPTION_TABLE_HEADER_HPP -#define TEACHOS_KAPI_ACPI_SYSTEM_DESCRIPTION_TABLE_HEADER_HPP - -// IWYU pragma: private, include "kapi/acpi.hpp" - -#include "kapi/acpi/table_type.hpp" - -#include - -#include -#include -#include - -namespace kapi::acpi -{ - - //! @addtogroup kapi-acpi-kernel-defined - //! @{ - - //! The common header of all System Description Tables. - struct [[gnu::packed]] system_description_table_header - { - //! Get the revision of the utility used to create this table. - [[nodiscard]] auto creator_revision() const noexcept -> std::uint32_t; - - //! Get the vendor ID of the utility used to create this table. - [[nodiscard]] auto creator_id() const noexcept -> std::uint32_t; - - //! Get the length of the entire table, including this header. - [[nodiscard]] auto length() const noexcept -> kstd::units::bytes; - - //! Get the ID of the OEM. - [[nodiscard]] auto oem_id() const noexcept -> std::string_view; - - //! Get the OEMs revision number of this table. - [[nodiscard]] auto oem_revision() const noexcept -> std::uint32_t; - - //! Get the OEMs ID of this table. - [[nodiscard]] auto oem_table_id() const noexcept -> std::string_view; - - //! Get the revision number of the structure of this table. - [[nodiscard]] auto revision() const noexcept -> std::uint8_t; - - //! Get the signature of this table. - [[nodiscard]] auto signature() const noexcept -> std::string_view; - - private: - std::array m_signature; - std::uint32_t m_length; - std::uint8_t m_revision; - [[maybe_unused]] std::uint8_t m_checksum; - std::array m_oem_id; - std::array m_oem_table_id; - std::uint32_t m_oem_revision; - std::uint32_t m_creator_id; - std::uint32_t m_creator_revision; - }; - - //! @} - // - //! @addtogroup kapi-acpi - //! @{ - - constexpr char const rsdt_table_signature[] = "RSDT"; // NOLINT - - template<> - struct table_type - { - using type = system_description_table_header; - }; - - //! @} - -} // namespace kapi::acpi - -#endif diff --git a/kapi/include/kapi/acpi/table_iterator.hpp b/kapi/include/kapi/acpi/table_iterator.hpp deleted file mode 100644 index 998d6d6..0000000 --- a/kapi/include/kapi/acpi/table_iterator.hpp +++ /dev/null @@ -1,64 +0,0 @@ -#ifndef TEACHOS_KAPI_ACPI_TABLE_ITERATOR_HPP -#define TEACHOS_KAPI_ACPI_TABLE_ITERATOR_HPP - -#include -#include -#include - -namespace kapi::acpi -{ - - template - struct table_iterator - { - using iterator_category = std::forward_iterator_tag; - using value_type = EntryType; - using pointer = value_type *; - using reference = value_type &; - using difference_type = std::ptrdiff_t; - - constexpr table_iterator() noexcept = default; - - constexpr table_iterator(pointer entry, pointer limit) noexcept - : m_entry{entry} - , m_limit{limit} - {} - - constexpr auto operator++() noexcept -> table_iterator & - { - auto decayed = std::bit_cast(m_entry); - decayed += m_entry->length(); - m_entry = std::bit_cast(decayed); - return *this; - } - - constexpr auto operator++(int) noexcept -> table_iterator - { - auto copy = *this; - ++*this; - return copy; - } - - constexpr auto operator*() const noexcept -> reference - { - return *m_entry; - } - - constexpr auto operator==(table_iterator const & other) const noexcept -> bool - { - return m_entry == other.m_entry || (is_end() && other.is_end()); - } - - private: - [[nodiscard]] constexpr auto is_end() const noexcept -> bool - { - return m_entry == m_limit; - } - - pointer m_entry{}; - pointer m_limit{}; - }; - -} // namespace kapi::acpi - -#endif diff --git a/kapi/include/kapi/acpi/table_type.hpp b/kapi/include/kapi/acpi/table_type.hpp deleted file mode 100644 index e088a24..0000000 --- a/kapi/include/kapi/acpi/table_type.hpp +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef TEACHOS_KAPI_ACPI_TABLE_TYPE_HPP -#define TEACHOS_KAPI_ACPI_TABLE_TYPE_HPP - -// IWYU pragma: private - -namespace kapi::acpi -{ - - //! @addtogroup kapi-acpi-kernel-defined - //! @{ - - template - struct table_type; - - template - using table_type_t = typename table_type::type; - - //! @} - -} // namespace kapi::acpi - -#endif diff --git a/kernel/CMakeLists.txt b/kernel/CMakeLists.txt index b9e01eb..74233cb 100644 --- a/kernel/CMakeLists.txt +++ b/kernel/CMakeLists.txt @@ -1,9 +1,6 @@ add_library("kernel_objs" OBJECT # Platform-independent KAPI implementation "kapi/acpi.cpp" - "kapi/acpi/multiple_apic_description_table.cpp" - "kapi/acpi/pointers.cpp" - "kapi/acpi/system_description_table_header.cpp" "kapi/boot_modules.cpp" "kapi/cio.cpp" "kapi/cpu.cpp" diff --git a/kernel/include/kernel/acpi/manager.hpp b/kernel/include/kernel/acpi/manager.hpp index fae59a6..420b44a 100644 --- a/kernel/include/kernel/acpi/manager.hpp +++ b/kernel/include/kernel/acpi/manager.hpp @@ -1,12 +1,12 @@ #ifndef TEACHOS_KERNEL_ACPI_MANAGER_HPP #define TEACHOS_KERNEL_ACPI_MANAGER_HPP -#include "kapi/acpi.hpp" - #include #include #include +#include + #include namespace kernel::acpi @@ -14,16 +14,16 @@ namespace kernel::acpi struct manager { - explicit manager(kapi::acpi::root_system_description_pointer const & sdp); + explicit manager(::acpi::rsdp const & sdp); auto load_tables() -> bool; - auto get_table(std::string_view signature) -> kstd::observer_ptr; + auto get_table(std::string_view signature) -> kstd::observer_ptr<::acpi::sdt const>; private: - kapi::acpi::root_system_description_pointer const * m_sdp{}; - kapi::acpi::system_description_table_header const * m_rsdt{}; - kstd::flat_map m_tables{}; + ::acpi::rsdp const * m_sdp{}; + ::acpi::sdt const * m_rsdt{}; + kstd::flat_map m_tables{}; bool m_extended{}; }; diff --git a/kernel/kapi/acpi.cpp b/kernel/kapi/acpi.cpp index e7c4921..df2bf05 100644 --- a/kernel/kapi/acpi.cpp +++ b/kernel/kapi/acpi.cpp @@ -6,12 +6,10 @@ #include -#include +#include + #include -#include -#include #include -#include #include namespace kapi::acpi @@ -22,7 +20,7 @@ namespace kapi::acpi auto constinit manager = std::optional{}; } // namespace - auto init(root_system_description_pointer const & sdp) -> bool + auto init(::acpi::rsdp const & sdp) -> bool { auto static constinit initialized = std::atomic_flag{}; if (initialized.test_and_set()) @@ -34,15 +32,7 @@ namespace kapi::acpi 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; - } - - auto get_table(std::string_view signature) -> kstd::observer_ptr + auto get_table(std::string_view signature) -> kstd::observer_ptr<::acpi::sdt const> { return manager->get_table(signature); } diff --git a/kernel/kapi/acpi/multiple_apic_description_table.cpp b/kernel/kapi/acpi/multiple_apic_description_table.cpp deleted file mode 100644 index c0360a3..0000000 --- a/kernel/kapi/acpi/multiple_apic_description_table.cpp +++ /dev/null @@ -1,70 +0,0 @@ -#include "kapi/acpi.hpp" -#include "kapi/memory.hpp" - -#include -#include - -namespace kapi::acpi -{ - - auto multiple_apic_description_table::local_interrupt_controller_address() const noexcept -> memory::physical_address - { - return memory::physical_address{static_cast(m_local_interrupt_controller_address)}; - } - - auto multiple_apic_description_table::flags() const noexcept -> std::uint32_t - { - return m_flags; - } - - auto multiple_apic_description_table_entry::type() const noexcept -> types - { - return static_cast(m_type); - } - - auto multiple_apic_description_table_entry::length() const noexcept -> std::size_t - { - return m_length; - } - - auto processor_local_apic::apic_id() const noexcept -> std::uint8_t - { - return m_apic_id; - } - - auto processor_local_apic::active_flags() const noexcept -> flags - { - return static_cast(m_flags); - } - - auto processor_local_apic::processor_id() const noexcept -> std::uint32_t - { - return m_processor_id; - } - - auto multiple_apic_description_table::begin() const noexcept -> iterator - { - auto base = reinterpret_cast(this); - base += sizeof(multiple_apic_description_table); - auto limit = reinterpret_cast(this); - limit += length().value; - return iterator{reinterpret_cast(base), - reinterpret_cast(limit)}; - } - - auto multiple_apic_description_table::cbegin() const noexcept -> iterator - { - return begin(); - } - - auto multiple_apic_description_table::end() const noexcept -> iterator - { - return {}; - } - - auto multiple_apic_description_table::cend() const noexcept -> iterator - { - return end(); - } - -} // namespace kapi::acpi diff --git a/kernel/kapi/acpi/pointers.cpp b/kernel/kapi/acpi/pointers.cpp deleted file mode 100644 index 63831e9..0000000 --- a/kernel/kapi/acpi/pointers.cpp +++ /dev/null @@ -1,55 +0,0 @@ -#include "kapi/acpi.hpp" -#include "kapi/memory.hpp" - -#include - -#include -#include -#include -#include - -namespace kapi::acpi -{ - - auto root_system_description_pointer::oem_id() const noexcept -> std::string_view - { - return {m_oem_id.data(), m_oem_id.size()}; - } - - auto root_system_description_pointer::revision() const noexcept -> std::uint8_t - { - return m_revision; - } - - auto root_system_description_pointer::signature() const noexcept -> std::string_view - { - return {m_signature.data(), m_signature.size()}; - } - - auto root_system_description_pointer::table_address() const noexcept -> memory::physical_address - { - auto raw = std::bit_cast(m_rsdt_address); - return memory::physical_address{static_cast(raw)}; - } - - auto root_system_description_pointer::validate() const noexcept -> bool - { - return validate_checksum({reinterpret_cast(this), sizeof(root_system_description_pointer)}); - } - - auto extended_system_description_pointer::length() const noexcept -> kstd::units::bytes - { - return kstd::units::bytes{m_length}; - } - - auto extended_system_description_pointer::table_address() const noexcept -> memory::physical_address - { - return memory::physical_address{std::bit_cast(m_xsdt_address)}; - } - - auto extended_system_description_pointer::validate() const noexcept -> bool - { - return validate_checksum({reinterpret_cast(this), m_length}); - } - -} // namespace kapi::acpi diff --git a/kernel/kapi/acpi/system_description_table_header.cpp b/kernel/kapi/acpi/system_description_table_header.cpp deleted file mode 100644 index f688b4d..0000000 --- a/kernel/kapi/acpi/system_description_table_header.cpp +++ /dev/null @@ -1,51 +0,0 @@ -#include "kapi/acpi.hpp" - -#include - -#include -#include - -namespace kapi::acpi -{ - - [[nodiscard]] auto system_description_table_header::creator_revision() const noexcept -> std::uint32_t - { - return m_creator_revision; - } - - [[nodiscard]] auto system_description_table_header::creator_id() const noexcept -> std::uint32_t - { - return m_creator_id; - } - - [[nodiscard]] auto system_description_table_header::length() const noexcept -> kstd::units::bytes - { - return kstd::units::bytes{m_length}; - } - - [[nodiscard]] auto system_description_table_header::oem_id() const noexcept -> std::string_view - { - return {m_oem_id.data(), m_oem_id.size()}; - } - - [[nodiscard]] auto system_description_table_header::oem_revision() const noexcept -> std::uint32_t - { - return m_oem_revision; - } - - [[nodiscard]] auto system_description_table_header::oem_table_id() const noexcept -> std::string_view - { - return {m_oem_table_id.data(), m_oem_table_id.size()}; - } - - [[nodiscard]] auto system_description_table_header::revision() const noexcept -> std::uint8_t - { - return m_revision; - } - - [[nodiscard]] auto system_description_table_header::signature() const noexcept -> std::string_view - { - return {m_signature.data(), m_signature.size()}; - } - -} // namespace kapi::acpi diff --git a/kernel/src/acpi/manager.cpp b/kernel/src/acpi/manager.cpp index 300b85e..501ce92 100644 --- a/kernel/src/acpi/manager.cpp +++ b/kernel/src/acpi/manager.cpp @@ -1,12 +1,13 @@ #include "kernel/acpi/manager.hpp" -#include "kapi/acpi.hpp" #include "kapi/memory.hpp" #include "kapi/system.hpp" #include #include +#include + #include #include #include @@ -14,7 +15,7 @@ namespace kernel::acpi { - manager::manager(kapi::acpi::root_system_description_pointer const & sdp) + manager::manager(::acpi::rsdp const & sdp) : m_sdp{&sdp} { if (m_sdp->signature() != "RSD PTR ") @@ -24,14 +25,14 @@ namespace kernel::acpi if (m_sdp->revision() >= 2) { - auto const xsdp = static_cast(m_sdp); + auto const xsdp = static_cast<::acpi::xsdp const *>(m_sdp); if (!xsdp->validate()) { kapi::system::panic("[OS:ACPI] Invalid XSDP signature!"); } - auto physical_extended_table_address = xsdp->table_address(); + auto physical_extended_table_address = kapi::memory::physical_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_rsdt = static_cast<::acpi::sdt const *>(linear_extended_table_address); m_extended = true; } else @@ -40,23 +41,22 @@ namespace kernel::acpi { kapi::system::panic("[OS:ACPI] Invalid RSDP checksum!"); } - auto physical_root_table_address = m_sdp->table_address(); + auto physical_root_table_address = kapi::memory::physical_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); + m_rsdt = static_cast<::acpi::sdt const *>(linear_root_table_address); } } auto manager::load_tables() -> bool { - if (!kapi::acpi::validate_checksum({reinterpret_cast(m_rsdt), m_rsdt->length().value})) + if (!::acpi::validate_checksum({reinterpret_cast(m_rsdt), m_rsdt->length().value})) { kapi::system::panic("[OS:ACPI] Invalid RSDT checksum!"); } auto entry_size = m_extended ? sizeof(std::uint64_t) : sizeof(std::uint32_t); - auto entry_count = (m_rsdt->length().value - sizeof(kapi::acpi::system_description_table_header)) / entry_size; - auto entries_base = - reinterpret_cast(m_rsdt) + sizeof(kapi::acpi::system_description_table_header); + auto entry_count = (m_rsdt->length().value - sizeof(::acpi::sdt)) / entry_size; + auto entries_base = reinterpret_cast(m_rsdt) + sizeof(::acpi::sdt); for (std::size_t i = 0; i < entry_count; ++i) { @@ -74,9 +74,9 @@ namespace kernel::acpi } auto linear_table_address = kapi::memory::hhdm_to_linear(physical_table_address); - auto table = static_cast(linear_table_address); + auto table = static_cast<::acpi::sdt const *>(linear_table_address); - if (!kapi::acpi::validate_checksum({reinterpret_cast(table), table->length().value})) + if (!::acpi::validate_checksum({reinterpret_cast(table), table->length().value})) { kstd::println(kstd::print_sink::stderr, "[OS:ACPI] Invalid table checksum!"); } @@ -90,8 +90,7 @@ namespace kernel::acpi return !m_tables.empty(); } - auto manager::get_table(std::string_view signature) - -> kstd::observer_ptr + auto manager::get_table(std::string_view signature) -> kstd::observer_ptr<::acpi::sdt const> { if (m_tables.contains(signature)) { diff --git a/libs/CMakeLists.txt b/libs/CMakeLists.txt index 58d9796..2b61992 100644 --- a/libs/CMakeLists.txt +++ b/libs/CMakeLists.txt @@ -1,3 +1,4 @@ +add_subdirectory("acpi" EXCLUDE_FROM_ALL SYSTEM) add_subdirectory("elf" EXCLUDE_FROM_ALL SYSTEM) add_subdirectory("kstd" EXCLUDE_FROM_ALL SYSTEM) -add_subdirectory("multiboot2" EXCLUDE_FROM_ALL SYSTEM) \ No newline at end of file +add_subdirectory("multiboot2" EXCLUDE_FROM_ALL SYSTEM) diff --git a/libs/acpi/CMakeLists.txt b/libs/acpi/CMakeLists.txt new file mode 100644 index 0000000..c6e63b9 --- /dev/null +++ b/libs/acpi/CMakeLists.txt @@ -0,0 +1,29 @@ +add_library("acpi" STATIC) +add_library("libs::acpi" ALIAS "acpi") + +target_include_directories("acpi" PUBLIC + "${CMAKE_CURRENT_SOURCE_DIR}" +) + +file(GLOB_RECURSE ACPI_HEADERS + RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} + "acpi/*.hpp" +) + +target_sources("acpi" PRIVATE + "acpi/checksum.cpp" + "acpi/madt.cpp" + "acpi/pointers.cpp" + "acpi/sdt.cpp" +) + +target_sources("acpi" PUBLIC + FILE_SET HEADERS + BASE_DIRS "acpi" + FILES + ${ACPI_HEADERS} +) + +target_link_libraries("acpi" PUBLIC + "libs::kstd" +) diff --git a/libs/acpi/acpi/acpi.hpp b/libs/acpi/acpi/acpi.hpp new file mode 100644 index 0000000..fb358cc --- /dev/null +++ b/libs/acpi/acpi/acpi.hpp @@ -0,0 +1,10 @@ +#ifndef ACPI_ACPI_HPP +#define ACPI_ACPI_HPP + +#include // IWYU pragma: export +#include // IWYU pragma: export +#include // IWYU pragma: export +#include // IWYU pragma: export +#include // IWYU pragma: export + +#endif diff --git a/libs/acpi/acpi/checksum.cpp b/libs/acpi/acpi/checksum.cpp new file mode 100644 index 0000000..56275c8 --- /dev/null +++ b/libs/acpi/acpi/checksum.cpp @@ -0,0 +1,19 @@ +#include + +#include +#include +#include +#include + +namespace acpi +{ + + 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 acpi diff --git a/libs/acpi/acpi/checksum.hpp b/libs/acpi/acpi/checksum.hpp new file mode 100644 index 0000000..a92c242 --- /dev/null +++ b/libs/acpi/acpi/checksum.hpp @@ -0,0 +1,20 @@ +#ifndef ACPI_CHECKSUM_HPP +#define ACPI_CHECKSUM_HPP + +// IWYU pragma: private, include + +#include +#include + +namespace acpi +{ + + //! 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 acpi + +#endif diff --git a/libs/acpi/acpi/madt.cpp b/libs/acpi/acpi/madt.cpp new file mode 100644 index 0000000..40289cf --- /dev/null +++ b/libs/acpi/acpi/madt.cpp @@ -0,0 +1,68 @@ +#include + +#include +#include + +namespace acpi +{ + + auto madt::local_interrupt_controller_address() const noexcept -> std::uintptr_t + { + return static_cast(m_local_interrupt_controller_address); + } + + auto madt::flags() const noexcept -> std::uint32_t + { + return m_flags; + } + + auto madt_entry::type() const noexcept -> types + { + return static_cast(m_type); + } + + auto madt_entry::length() const noexcept -> std::size_t + { + return m_length; + } + + auto processor_local_apic::apic_id() const noexcept -> std::uint8_t + { + return m_apic_id; + } + + auto processor_local_apic::active_flags() const noexcept -> flags + { + return static_cast(m_flags); + } + + auto processor_local_apic::processor_id() const noexcept -> std::uint32_t + { + return m_processor_id; + } + + auto madt::begin() const noexcept -> iterator + { + auto base = reinterpret_cast(this); + base += sizeof(madt); + auto limit = reinterpret_cast(this); + limit += length().value; + return iterator{reinterpret_cast(base), reinterpret_cast(limit)}; + } + + auto madt::cbegin() const noexcept -> iterator + { + return begin(); + } + + auto madt::end() const noexcept -> iterator + { + return {}; + } + + auto madt::cend() const noexcept -> iterator + { + return end(); + } + +} // namespace acpi diff --git a/libs/acpi/acpi/madt.hpp b/libs/acpi/acpi/madt.hpp new file mode 100644 index 0000000..f680430 --- /dev/null +++ b/libs/acpi/acpi/madt.hpp @@ -0,0 +1,92 @@ +#ifndef ACPI_ACPI_MADT_HPP +#define ACPI_ACPI_MADT_HPP + +// IWYU pragma: private, include + +#include +#include + +#include +#include + +#include +#include +#include + +namespace acpi +{ + + struct [[gnu::packed]] madt_entry + { + enum struct types : std::uint8_t + { + processor_local_apic, + io_apic, + io_apic_interrupt_source_override, + io_apic_nmi_source, + local_apic_nmi_interrupts, + local_apic_address_override, + processor_local_x2_apic, + }; + + [[nodiscard]] auto type() const noexcept -> types; + [[nodiscard]] auto length() const noexcept -> std::size_t; + + private: + std::uint8_t m_type; + std::uint8_t m_length; + }; + + //! The common header for all + struct [[gnu::packed]] madt : sdt + { + using iterator = sdt_iterator; + using const_iterator = iterator; + + [[nodiscard]] auto local_interrupt_controller_address() const noexcept -> std::uintptr_t; + [[nodiscard]] auto flags() const noexcept -> std::uint32_t; + + [[nodiscard]] auto begin() const noexcept -> iterator; + [[nodiscard]] auto cbegin() const noexcept -> iterator; + [[nodiscard]] auto end() const noexcept -> iterator; + [[nodiscard]] auto cend() const noexcept -> iterator; + + private: + std::uint32_t m_local_interrupt_controller_address; + std::uint32_t m_flags; + }; + + struct [[gnu::packed]] processor_local_apic : madt_entry + { + enum struct flags : std::uint32_t + { + processor_enabled = 1, + online_capable = 2, + }; + + [[nodiscard]] auto apic_id() const noexcept -> std::uint8_t; + [[nodiscard]] auto active_flags() const noexcept -> flags; + [[nodiscard]] auto processor_id() const noexcept -> std::uint32_t; + + private: + std::uint8_t m_processor_id; + std::uint8_t m_apic_id; + std::uint32_t m_flags; + }; + + constexpr char const madt_table_signature[] = "APIC"; // NOLINT + + template<> + struct table_type + { + using type = madt; + }; + +} // namespace acpi + +template<> +struct kstd::ext::is_bitfield_enum : std::true_type +{ +}; + +#endif diff --git a/libs/acpi/acpi/pointers.cpp b/libs/acpi/acpi/pointers.cpp new file mode 100644 index 0000000..b206cc6 --- /dev/null +++ b/libs/acpi/acpi/pointers.cpp @@ -0,0 +1,55 @@ +#include + +#include +#include + +#include +#include +#include +#include + +namespace acpi +{ + + auto rsdp::oem_id() const noexcept -> std::string_view + { + return {m_oem_id.data(), m_oem_id.size()}; + } + + auto rsdp::revision() const noexcept -> std::uint8_t + { + return m_revision; + } + + auto rsdp::signature() const noexcept -> std::string_view + { + return {m_signature.data(), m_signature.size()}; + } + + auto rsdp::table_address() const noexcept -> std::uintptr_t + { + auto raw = std::bit_cast(m_rsdt_address); + return static_cast(raw); + } + + auto rsdp::validate() const noexcept -> bool + { + return validate_checksum({reinterpret_cast(this), sizeof(rsdp)}); + } + + auto xsdp::length() const noexcept -> kstd::units::bytes + { + return kstd::units::bytes{m_length}; + } + + auto xsdp::table_address() const noexcept -> std::uintptr_t + { + return std::bit_cast(m_xsdt_address); + } + + auto xsdp::validate() const noexcept -> bool + { + return validate_checksum({reinterpret_cast(this), m_length}); + } + +} // namespace acpi diff --git a/libs/acpi/acpi/pointers.hpp b/libs/acpi/acpi/pointers.hpp new file mode 100644 index 0000000..5771e7d --- /dev/null +++ b/libs/acpi/acpi/pointers.hpp @@ -0,0 +1,72 @@ +#ifndef ACPI_POINTERS_HPP +#define ACPI_POINTERS_HPP + +// IWYU pragma: private, include + +#include + +#include +#include +#include +#include + +namespace acpi +{ + + //! A pointer to the Root System Description Table. + struct [[gnu::packed]] rsdp + { + //! Get the ID of the OEM, usually a vendor name. + [[nodiscard]] auto oem_id() const noexcept -> std::string_view; + + //! Get the revision of the ACPI Root System Description Table. + //! + //! @note Revisions greater or equal to two indicate that the system uses the Extended System Description Table, and + //! as such that table should be use to query information. + [[nodiscard]] auto revision() const noexcept -> std::uint8_t; + + //! Get the signature of this pointer. + //! + //! A valid RSDP must always carry the signature "RSD PTR ". + [[nodiscard]] auto signature() const noexcept -> std::string_view; + + //! Get the physical address of the pointed-to Root System Description Table. + [[nodiscard]] auto table_address() const noexcept -> std::uintptr_t; + + //! Validate the checksum of this RSDP. + //! + //! @return @p true iff. the checksum of this RSDP is valid, @p false otherwise. + [[nodiscard]] auto validate() const noexcept -> bool; + + private: + std::array m_signature; + [[maybe_unused]] std::uint8_t m_checksum; + std::array m_oem_id; + std::uint8_t m_revision; + std::array m_rsdt_address; + }; + + //! A pointer to the Extended System Description Table. + struct [[gnu::packed]] xsdp : rsdp + { + //! Get the length of the data contained in this pointer. + [[nodiscard]] auto length() const noexcept -> kstd::units::bytes; + + //! Get the physical address of the pointed-to Extended System Description Table. + [[nodiscard]] auto table_address() const noexcept -> std::uintptr_t; + + //! Validate the checksum of this XSDP. + //! + //! @return @p true iff. the checksum of this RSDP is valid, @p false otherwise. + [[nodiscard]] auto validate() const noexcept -> bool; + + private: + std::uint32_t m_length; + std::array m_xsdt_address; + [[maybe_unused]] std::uint8_t m_extended_checksum; + [[maybe_unused]] std::array m_reserved; + }; + +} // namespace acpi + +#endif diff --git a/libs/acpi/acpi/sdt.cpp b/libs/acpi/acpi/sdt.cpp new file mode 100644 index 0000000..c2b9d68 --- /dev/null +++ b/libs/acpi/acpi/sdt.cpp @@ -0,0 +1,51 @@ +#include + +#include + +#include +#include + +namespace acpi +{ + + auto sdt::creator_revision() const noexcept -> std::uint32_t + { + return m_creator_revision; + } + + auto sdt::creator_id() const noexcept -> std::uint32_t + { + return m_creator_id; + } + + auto sdt::length() const noexcept -> kstd::units::bytes + { + return kstd::units::bytes{m_length}; + } + + auto sdt::oem_id() const noexcept -> std::string_view + { + return {m_oem_id.data(), m_oem_id.size()}; + } + + auto sdt::oem_revision() const noexcept -> std::uint32_t + { + return m_oem_revision; + } + + auto sdt::oem_table_id() const noexcept -> std::string_view + { + return {m_oem_table_id.data(), m_oem_table_id.size()}; + } + + auto sdt::revision() const noexcept -> std::uint8_t + { + return m_revision; + } + + auto sdt::signature() const noexcept -> std::string_view + { + return {m_signature.data(), m_signature.size()}; + } + +} // namespace acpi diff --git a/libs/acpi/acpi/sdt.hpp b/libs/acpi/acpi/sdt.hpp new file mode 100644 index 0000000..9e5ec89 --- /dev/null +++ b/libs/acpi/acpi/sdt.hpp @@ -0,0 +1,119 @@ +#ifndef ACPI_SDT_HPP +#define ACPI_SDT_HPP + +// IWYU pragma: private, include + +#include + +#include + +#include +#include +#include +#include +#include + +namespace acpi +{ + + template + struct sdt_iterator + { + using iterator_category = std::forward_iterator_tag; + using value_type = EntryType; + using pointer = value_type *; + using reference = value_type &; + using difference_type = std::ptrdiff_t; + + constexpr sdt_iterator() noexcept = default; + + constexpr sdt_iterator(pointer entry, pointer limit) noexcept + : m_entry{entry} + , m_limit{limit} + {} + + constexpr auto operator++() noexcept -> sdt_iterator & + { + auto decayed = std::bit_cast(m_entry); + decayed += m_entry->length(); + m_entry = std::bit_cast(decayed); + return *this; + } + + constexpr auto operator++(int) noexcept -> sdt_iterator + { + auto copy = *this; + ++*this; + return copy; + } + + constexpr auto operator*() const noexcept -> reference + { + return *m_entry; + } + + constexpr auto operator==(sdt_iterator const & other) const noexcept -> bool + { + return m_entry == other.m_entry || (is_end() && other.is_end()); + } + + private: + [[nodiscard]] constexpr auto is_end() const noexcept -> bool + { + return m_entry == m_limit; + } + + pointer m_entry{}; + pointer m_limit{}; + }; + + //! The common base of all System Description Tables. + struct [[gnu::packed]] sdt + { + //! Get the revision of the utility used to create this table. + [[nodiscard]] auto creator_revision() const noexcept -> std::uint32_t; + + //! Get the vendor ID of the utility used to create this table. + [[nodiscard]] auto creator_id() const noexcept -> std::uint32_t; + + //! Get the length of the entire table, including this header. + [[nodiscard]] auto length() const noexcept -> kstd::units::bytes; + + //! Get the ID of the OEM. + [[nodiscard]] auto oem_id() const noexcept -> std::string_view; + + //! Get the OEMs revision number of this table. + [[nodiscard]] auto oem_revision() const noexcept -> std::uint32_t; + + //! Get the OEMs ID of this table. + [[nodiscard]] auto oem_table_id() const noexcept -> std::string_view; + + //! Get the revision number of the structure of this table. + [[nodiscard]] auto revision() const noexcept -> std::uint8_t; + + //! Get the signature of this table. + [[nodiscard]] auto signature() const noexcept -> std::string_view; + + private: + std::array m_signature; + std::uint32_t m_length; + std::uint8_t m_revision; + [[maybe_unused]] std::uint8_t m_checksum; + std::array m_oem_id; + std::array m_oem_table_id; + std::uint32_t m_oem_revision; + std::uint32_t m_creator_id; + std::uint32_t m_creator_revision; + }; + + constexpr char const rsdt_table_signature[] = "RSDT"; // NOLINT + + template<> + struct table_type + { + using type = sdt; + }; + +} // namespace acpi + +#endif diff --git a/libs/acpi/acpi/table_type.hpp b/libs/acpi/acpi/table_type.hpp new file mode 100644 index 0000000..7fdd7e3 --- /dev/null +++ b/libs/acpi/acpi/table_type.hpp @@ -0,0 +1,17 @@ +#ifndef ACPI_TABLE_TYPE_HPP +#define ACPI_TABLE_TYPE_HPP + +// IWYU pragma: private, include + +namespace acpi +{ + + template + struct table_type; + + template + using table_type_t = typename table_type::type; + +} // namespace acpi + +#endif -- cgit v1.2.3