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 --- 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 ++++++ 11 files changed, 552 insertions(+) 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 (limited to 'libs/acpi') 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 From eacc1becd1308a01a7ffcddf7c8910c8dc708939 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Tue, 14 Apr 2026 13:52:19 +0200 Subject: acpi: begin test implementation --- libs/acpi/CMakeLists.txt | 19 +++++++++++++++++++ libs/acpi/acpi/pointers.cpp | 4 ++-- libs/acpi/acpi/pointers.test.cpp | 29 +++++++++++++++++++++++++++++ 3 files changed, 50 insertions(+), 2 deletions(-) create mode 100644 libs/acpi/acpi/pointers.test.cpp (limited to 'libs/acpi') diff --git a/libs/acpi/CMakeLists.txt b/libs/acpi/CMakeLists.txt index c6e63b9..b8face4 100644 --- a/libs/acpi/CMakeLists.txt +++ b/libs/acpi/CMakeLists.txt @@ -27,3 +27,22 @@ target_sources("acpi" PUBLIC target_link_libraries("acpi" PUBLIC "libs::kstd" ) + +if(NOT CMAKE_CROSSCOMPILING) + add_executable("acpi_tests" + "acpi/pointers.test.cpp" + ) + + target_link_libraries("acpi_tests" PRIVATE + "Catch2::Catch2WithMain" + "libs::acpi" + ) + + set_target_properties("acpi_tests" PROPERTIES + C_CLANG_TIDY "" + CXX_CLANG_TIDY "" + EXCLUDE_FROM_ALL NO + ) + + catch_discover_tests("acpi_tests") +endif() diff --git a/libs/acpi/acpi/pointers.cpp b/libs/acpi/acpi/pointers.cpp index b206cc6..8a8629f 100644 --- a/libs/acpi/acpi/pointers.cpp +++ b/libs/acpi/acpi/pointers.cpp @@ -34,7 +34,7 @@ namespace acpi auto rsdp::validate() const noexcept -> bool { - return validate_checksum({reinterpret_cast(this), sizeof(rsdp)}); + return signature() == "RSD PTR " && validate_checksum({reinterpret_cast(this), sizeof(rsdp)}); } auto xsdp::length() const noexcept -> kstd::units::bytes @@ -49,7 +49,7 @@ namespace acpi auto xsdp::validate() const noexcept -> bool { - return validate_checksum({reinterpret_cast(this), m_length}); + return signature() == "RSD PTR " && validate_checksum({reinterpret_cast(this), m_length}); } } // namespace acpi diff --git a/libs/acpi/acpi/pointers.test.cpp b/libs/acpi/acpi/pointers.test.cpp new file mode 100644 index 0000000..06ce1a4 --- /dev/null +++ b/libs/acpi/acpi/pointers.test.cpp @@ -0,0 +1,29 @@ +#include +#include + +#include +#include +#include + +SCENARIO("ACPI root pointer parsing", "[acpi]") +{ + GIVEN("A null-filled pointer") + { + auto data = std::array{}; + + WHEN("parsing the data") + { + auto rsdp = std::bit_cast(data); + + THEN("the signature is invalid") + { + REQUIRE(rsdp.signature() != "RSD PTR "); + } + + THEN("validate returns false") + { + REQUIRE_FALSE(rsdp.validate()); + } + } + } +} -- cgit v1.2.3 From 1fa31688a0e237dec1170dcea9e8f0a0571a25e5 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Wed, 15 Apr 2026 08:55:03 +0200 Subject: acpi: add basic MADT tests --- libs/acpi/CMakeLists.txt | 34 +++++++++++++++++++++++ libs/acpi/acpi/madt.cpp | 10 +++++-- libs/acpi/acpi/madt.hpp | 38 +++++++++++++++++++++++--- libs/acpi/acpi/madt.test.cpp | 55 ++++++++++++++++++++++++++++++++++++++ libs/acpi/acpi/sdt.cpp | 7 +++++ libs/acpi/acpi/sdt.hpp | 8 ++++++ libs/acpi/test_data/basic_madt.asl | 29 ++++++++++++++++++++ libs/acpi/test_data/basic_rsdt.asl | 26 ++++++++++++++++++ libs/acpi/test_data/tables.S | 14 ++++++++++ libs/acpi/test_data/tables.hpp | 25 +++++++++++++++++ 10 files changed, 241 insertions(+), 5 deletions(-) create mode 100644 libs/acpi/acpi/madt.test.cpp create mode 100644 libs/acpi/test_data/basic_madt.asl create mode 100644 libs/acpi/test_data/basic_rsdt.asl create mode 100644 libs/acpi/test_data/tables.S create mode 100644 libs/acpi/test_data/tables.hpp (limited to 'libs/acpi') diff --git a/libs/acpi/CMakeLists.txt b/libs/acpi/CMakeLists.txt index b8face4..8ace42d 100644 --- a/libs/acpi/CMakeLists.txt +++ b/libs/acpi/CMakeLists.txt @@ -1,3 +1,11 @@ +cmake_minimum_required(VERSION "3.27.0") + +project("acpi" + DESCRIPTION "An ACPI parsing library" + VERSION "0.0.1" + LANGUAGES ASM CXX +) + add_library("acpi" STATIC) add_library("libs::acpi" ALIAS "acpi") @@ -29,8 +37,34 @@ target_link_libraries("acpi" PUBLIC ) if(NOT CMAKE_CROSSCOMPILING) + find_program(IASL_EXE NAMES "iasl" REQUIRED) + + set(TEST_TABLES + "basic_madt" + "basic_rsdt" + ) + + foreach(TABLE IN LISTS TEST_TABLES) + add_custom_command(OUTPUT "test_data/${TABLE}.aml" + COMMAND "${IASL_EXE}" -p "test_data/${TABLE}.aml" "${CMAKE_CURRENT_SOURCE_DIR}/test_data/${TABLE}.asl" + DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/test_data/${TABLE}.asl" + COMMENT "Compiling test_data/${TABLE}.asl" + VERBATIM + ) + list(APPEND GENERATED_TABLE_BLOBS "${CMAKE_CURRENT_BINARY_DIR}/test_data/${TABLE}.aml") + endforeach() + + set_source_files_properties("test_data/tables.S" PROPERTIES OBJECT_DEPENDS "${GENERATED_TABLE_BLOBS}") + add_executable("acpi_tests" + "acpi/madt.test.cpp" "acpi/pointers.test.cpp" + + "test_data/tables.S" + ) + + target_include_directories("acpi_tests" PRIVATE + "${CMAKE_CURRENT_BINARY_DIR}/test_data" ) target_link_libraries("acpi_tests" PRIVATE diff --git a/libs/acpi/acpi/madt.cpp b/libs/acpi/acpi/madt.cpp index 40289cf..6a62f07 100644 --- a/libs/acpi/acpi/madt.cpp +++ b/libs/acpi/acpi/madt.cpp @@ -1,3 +1,4 @@ +#include #include #include @@ -16,9 +17,14 @@ namespace acpi return m_flags; } - auto madt_entry::type() const noexcept -> types + auto madt::validate() const noexcept -> bool { - return static_cast(m_type); + return signature() == madt_table_signature && sdt::validate(); + } + + auto madt_entry::type() const noexcept -> enum type + { + return static_cast(m_type); } auto madt_entry::length() const noexcept -> std::size_t diff --git a/libs/acpi/acpi/madt.hpp b/libs/acpi/acpi/madt.hpp index f680430..8b75f58 100644 --- a/libs/acpi/acpi/madt.hpp +++ b/libs/acpi/acpi/madt.hpp @@ -4,6 +4,7 @@ // IWYU pragma: private, include #include +#include #include #include @@ -11,6 +12,7 @@ #include #include +#include #include namespace acpi @@ -18,7 +20,8 @@ namespace acpi struct [[gnu::packed]] madt_entry { - enum struct types : std::uint8_t + //! The type of an MADT entry. + enum struct type : std::uint8_t { processor_local_apic, io_apic, @@ -29,28 +32,55 @@ namespace acpi processor_local_x2_apic, }; - [[nodiscard]] auto type() const noexcept -> types; + //! Get the type of this entry. + [[nodiscard]] auto type() const noexcept -> enum type; + + //! Get the length of this entry. [[nodiscard]] auto length() const noexcept -> std::size_t; + //! Cast this entry to the given concrete entry type. + //! + //! @warning This function will terminate execution if the desired target type does not match up with this entry's + //! actual type. + template + [[nodiscard]] auto as() const -> EntryType const & + { + if (type() != EntryType::this_type) + { + kstd::os::panic("Invalid cast"); + } + return reinterpret_cast(*this); + } + private: std::uint8_t m_type; std::uint8_t m_length; }; - //! The common header for all + //! The Multiple APIC Description Table (MADT) struct [[gnu::packed]] madt : sdt { using iterator = sdt_iterator; using const_iterator = iterator; + //! Get the physical address of the local interrupt controllers described by this entry. [[nodiscard]] auto local_interrupt_controller_address() const noexcept -> std::uintptr_t; + [[nodiscard]] auto flags() const noexcept -> std::uint32_t; + [[nodiscard]] auto validate() const noexcept -> bool; [[nodiscard]] auto begin() const noexcept -> iterator; [[nodiscard]] auto cbegin() const noexcept -> iterator; [[nodiscard]] auto end() const noexcept -> iterator; [[nodiscard]] auto cend() const noexcept -> iterator; + template + [[nodiscard]] auto only() const noexcept + { + return *this | std::views::filter([](auto const & e) { return e.type() == EntryType::this_type; }) | + std::views::transform([](auto const & e) { return e.template as(); }); + } + private: std::uint32_t m_local_interrupt_controller_address; std::uint32_t m_flags; @@ -58,6 +88,8 @@ namespace acpi struct [[gnu::packed]] processor_local_apic : madt_entry { + constexpr auto static this_type = type::processor_local_apic; + enum struct flags : std::uint32_t { processor_enabled = 1, diff --git a/libs/acpi/acpi/madt.test.cpp b/libs/acpi/acpi/madt.test.cpp new file mode 100644 index 0000000..8926192 --- /dev/null +++ b/libs/acpi/acpi/madt.test.cpp @@ -0,0 +1,55 @@ +#include + +#include +#include +#include + +#include + +SCENARIO("MADT parsing", "[madt]") +{ + GIVEN("The basic compiled MADT containing a single LAPIC entry and the default x86 LAPIC address") + { + auto data = acpi::test_data::tables::basic_madt(); + + WHEN("parsing the table") + { + auto madt = reinterpret_cast(data.data()); + + THEN("the signature is correct") + { + REQUIRE(madt->signature() == "APIC"); + } + + THEN("validate returns true") + { + REQUIRE(madt->validate()); + } + + THEN("there is a single entry in the table") + { + REQUIRE(std::distance(madt->begin(), madt->end()) == 1); + } + + THEN("the LAPIC address is 0xfee00000") + { + REQUIRE(madt->local_interrupt_controller_address() == 0xfee0'0000); + } + + THEN("the length is sizeof(madt) + sizeof(processor_local_apic)") + { + REQUIRE(madt->length() == kstd::type_size + kstd::type_size); + } + + THEN("the first entry has type processor_local_apic") + { + REQUIRE(madt->cbegin()->type() == acpi::madt_entry::type::processor_local_apic); + } + + THEN("`only` can be used to get a view of all processor_local_apic entries") + { + REQUIRE(std::ranges::distance(madt->only()) == 1); + } + } + } +} diff --git a/libs/acpi/acpi/sdt.cpp b/libs/acpi/acpi/sdt.cpp index c2b9d68..6c6cb47 100644 --- a/libs/acpi/acpi/sdt.cpp +++ b/libs/acpi/acpi/sdt.cpp @@ -1,7 +1,9 @@ #include +#include #include +#include #include #include @@ -48,4 +50,9 @@ namespace acpi return {m_signature.data(), m_signature.size()}; } + auto sdt::validate() const noexcept -> bool + { + return acpi::validate_checksum({reinterpret_cast(this), length().value}); + } + } // namespace acpi diff --git a/libs/acpi/acpi/sdt.hpp b/libs/acpi/acpi/sdt.hpp index 9e5ec89..72b3896 100644 --- a/libs/acpi/acpi/sdt.hpp +++ b/libs/acpi/acpi/sdt.hpp @@ -52,6 +52,11 @@ namespace acpi return *m_entry; } + constexpr auto operator->() const noexcept -> pointer + { + return m_entry; + } + constexpr auto operator==(sdt_iterator const & other) const noexcept -> bool { return m_entry == other.m_entry || (is_end() && other.is_end()); @@ -94,6 +99,9 @@ namespace acpi //! Get the signature of this table. [[nodiscard]] auto signature() const noexcept -> std::string_view; + //! Valide this table's checksum + [[nodiscard]] auto validate() const noexcept -> bool; + private: std::array m_signature; std::uint32_t m_length; diff --git a/libs/acpi/test_data/basic_madt.asl b/libs/acpi/test_data/basic_madt.asl new file mode 100644 index 0000000..cd6958a --- /dev/null +++ b/libs/acpi/test_data/basic_madt.asl @@ -0,0 +1,29 @@ +/* + * Intel ACPI Component Architecture + * iASL Compiler/Disassembler version 20251212 (64-bit version) + * Copyright (c) 2000 - 2025 Intel Corporation + * + * Template for [APIC] ACPI Table (static data table) + * Format: [ByteLength] FieldName : HexFieldValue + */ +[0004] Signature : "APIC" [Multiple APIC Description Table (MADT)] +[0004] Table Length : 00000000 +[0001] Revision : 07 +[0001] Checksum : 00 +[0006] Oem ID : "INTEL " +[0008] Oem Table ID : "Template" +[0004] Oem Revision : 00000001 +[0004] Asl Compiler ID : "INTL" +[0004] Asl Compiler Revision : 20230628 + +[0004] Local Apic Address : FEE00000 +[0004] Flags (decoded below) : 00000001 + PC-AT Compatibility : 1 + +[0001] Subtable Type : 00 [Processor Local APIC] +[0001] Length : 08 +[0001] Processor ID : 00 +[0001] Local Apic ID : 00 +[0004] Flags (decoded below) : 00000001 + Processor Enabled : 1 + Runtime Online Capable : 0 diff --git a/libs/acpi/test_data/basic_rsdt.asl b/libs/acpi/test_data/basic_rsdt.asl new file mode 100644 index 0000000..6cf4c7a --- /dev/null +++ b/libs/acpi/test_data/basic_rsdt.asl @@ -0,0 +1,26 @@ +/* + * Intel ACPI Component Architecture + * iASL Compiler/Disassembler version 20251212 (64-bit version) + * Copyright (c) 2000 - 2025 Intel Corporation + * + * Template for [RSDT] ACPI Table (static data table) + * Format: [ByteLength] FieldName : HexFieldValue + */ +[0004] Signature : "RSDT" [Root System Description Table] +[0004] Table Length : 00000000 +[0001] Revision : 01 +[0001] Checksum : 00 +[0006] Oem ID : "INTEL " +[0008] Oem Table ID : "TEMPLATE" +[0004] Oem Revision : 00000001 +[0004] Asl Compiler ID : "INTL" +[0004] Asl Compiler Revision : 20100528 + +[0004] ACPI Table Address 0 : 00000010 +[0004] ACPI Table Address 1 : 00000020 +[0004] ACPI Table Address 2 : 00000030 +[0004] ACPI Table Address 3 : 00000040 +[0004] ACPI Table Address 4 : 00000050 +[0004] ACPI Table Address 5 : 00000060 +[0004] ACPI Table Address 6 : 00000070 +[0004] ACPI Table Address 7 : 00000080 diff --git a/libs/acpi/test_data/tables.S b/libs/acpi/test_data/tables.S new file mode 100644 index 0000000..af58109 --- /dev/null +++ b/libs/acpi/test_data/tables.S @@ -0,0 +1,14 @@ +.section .rodata + +.balign 16 + +#define TABLE(name, file) \ + .global name##_start; \ + .global name##_end; \ + name##_start: .incbin file; \ + name##_end: + +TABLE(basic_madt, "basic_madt.aml") +TABLE(basic_rsdt, "basic_rsdt.aml") + +#undef TABLE diff --git a/libs/acpi/test_data/tables.hpp b/libs/acpi/test_data/tables.hpp new file mode 100644 index 0000000..2b3874f --- /dev/null +++ b/libs/acpi/test_data/tables.hpp @@ -0,0 +1,25 @@ +#ifndef ACPI_TEST_DATA_TABLES_HPP +#define ACPI_TEST_DATA_TABLES_HPP + +#include +#include + +#define TABLE(name) \ + extern "C" std::byte const name##_start; \ + extern "C" std::byte const name##_end; \ + auto inline name()->std::span \ + { \ + return {&name##_start, &name##_end}; \ + } + +namespace acpi::test_data::tables +{ + + TABLE(basic_madt); + TABLE(basic_rsdt); + +} // namespace acpi::test_data::tables + +#undef TABLE + +#endif -- cgit v1.2.3 From 1113e812359a66591b0854a9f723ab8cd8b09274 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Wed, 15 Apr 2026 09:04:35 +0200 Subject: acpi: add rsdp test data --- libs/acpi/CMakeLists.txt | 1 + libs/acpi/test_data/basic_rsdp.asl | 16 ++++++++++++++++ libs/acpi/test_data/tables.S | 1 + libs/acpi/test_data/tables.hpp | 1 + 4 files changed, 19 insertions(+) create mode 100644 libs/acpi/test_data/basic_rsdp.asl (limited to 'libs/acpi') diff --git a/libs/acpi/CMakeLists.txt b/libs/acpi/CMakeLists.txt index 8ace42d..30e1aca 100644 --- a/libs/acpi/CMakeLists.txt +++ b/libs/acpi/CMakeLists.txt @@ -42,6 +42,7 @@ if(NOT CMAKE_CROSSCOMPILING) set(TEST_TABLES "basic_madt" "basic_rsdt" + "basic_rsdp" ) foreach(TABLE IN LISTS TEST_TABLES) diff --git a/libs/acpi/test_data/basic_rsdp.asl b/libs/acpi/test_data/basic_rsdp.asl new file mode 100644 index 0000000..8274c0f --- /dev/null +++ b/libs/acpi/test_data/basic_rsdp.asl @@ -0,0 +1,16 @@ +/* + * Intel ACPI Component Architecture + * iASL Compiler/Disassembler version 20251212 (64-bit version) + * Copyright (c) 2000 - 2025 Intel Corporation + * + * Template for [RSDP] ACPI Table (AML byte code table) + */ +[0008] Signature : "RSD PTR " +[0001] Checksum : 43 +[0006] Oem ID : "INTEL " +[0001] Revision : 02 +[0004] RSDT Address : 00000000 +[0004] Length : 00000024 +[0008] XSDT Address : 0000000000000000 +[0001] Extended Checksum : DC +[0003] Reserved : 000000 diff --git a/libs/acpi/test_data/tables.S b/libs/acpi/test_data/tables.S index af58109..f40f070 100644 --- a/libs/acpi/test_data/tables.S +++ b/libs/acpi/test_data/tables.S @@ -10,5 +10,6 @@ TABLE(basic_madt, "basic_madt.aml") TABLE(basic_rsdt, "basic_rsdt.aml") +TABLE(basic_rsdp, "basic_rsdp.aml") #undef TABLE diff --git a/libs/acpi/test_data/tables.hpp b/libs/acpi/test_data/tables.hpp index 2b3874f..510cbda 100644 --- a/libs/acpi/test_data/tables.hpp +++ b/libs/acpi/test_data/tables.hpp @@ -17,6 +17,7 @@ namespace acpi::test_data::tables TABLE(basic_madt); TABLE(basic_rsdt); + TABLE(basic_rsdp); } // namespace acpi::test_data::tables -- cgit v1.2.3 From 6344a2a81b94a00aaaa987d0e0d40993ed581d5e Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Wed, 15 Apr 2026 16:19:00 +0200 Subject: acpi: reimplement the common table header --- libs/acpi/CMakeLists.txt | 3 + libs/acpi/acpi/common/table_header.cpp | 130 ++++++++++++++++++++++++++++ libs/acpi/acpi/common/table_header.hpp | 57 ++++++++++++ libs/acpi/acpi/common/table_header.test.cpp | 58 +++++++++++++ libs/acpi/test_data/table_header.asl | 9 ++ libs/acpi/test_data/tables.S | 1 + libs/acpi/test_data/tables.hpp | 1 + 7 files changed, 259 insertions(+) create mode 100644 libs/acpi/acpi/common/table_header.cpp create mode 100644 libs/acpi/acpi/common/table_header.hpp create mode 100644 libs/acpi/acpi/common/table_header.test.cpp create mode 100644 libs/acpi/test_data/table_header.asl (limited to 'libs/acpi') diff --git a/libs/acpi/CMakeLists.txt b/libs/acpi/CMakeLists.txt index 30e1aca..b9c607d 100644 --- a/libs/acpi/CMakeLists.txt +++ b/libs/acpi/CMakeLists.txt @@ -20,6 +20,7 @@ file(GLOB_RECURSE ACPI_HEADERS target_sources("acpi" PRIVATE "acpi/checksum.cpp" + "acpi/common/table_header.cpp" "acpi/madt.cpp" "acpi/pointers.cpp" "acpi/sdt.cpp" @@ -43,6 +44,7 @@ if(NOT CMAKE_CROSSCOMPILING) "basic_madt" "basic_rsdt" "basic_rsdp" + "table_header" ) foreach(TABLE IN LISTS TEST_TABLES) @@ -58,6 +60,7 @@ if(NOT CMAKE_CROSSCOMPILING) set_source_files_properties("test_data/tables.S" PROPERTIES OBJECT_DEPENDS "${GENERATED_TABLE_BLOBS}") add_executable("acpi_tests" + "acpi/common/table_header.test.cpp" "acpi/madt.test.cpp" "acpi/pointers.test.cpp" diff --git a/libs/acpi/acpi/common/table_header.cpp b/libs/acpi/acpi/common/table_header.cpp new file mode 100644 index 0000000..17a8219 --- /dev/null +++ b/libs/acpi/acpi/common/table_header.cpp @@ -0,0 +1,130 @@ +#include +#include + +#include + +#include +#include +#include +#include +#include + +namespace acpi +{ + + struct common_table_header_data + { + 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::array creator_id; + std::uint32_t creator_revision; + }; + + static_assert(sizeof(common_table_header_data) == common_table_header_size); + + auto common_table_header::creator_revision() const noexcept -> decltype(common_table_header_data::creator_revision) + { + using type = decltype(common_table_header_data::creator_revision); + + constexpr auto size = sizeof(type); + constexpr auto offset = offsetof(common_table_header_data, creator_revision); + + auto const data = std::span{m_data.data() + offset, size}; + auto value = type{}; + + kstd::libc::memcpy(&value, data.data(), size); + + return value; + } + + auto common_table_header::creator_id() const noexcept -> std::string_view + { + constexpr auto size = sizeof(common_table_header_data::creator_id); + constexpr auto offset = offsetof(common_table_header_data, creator_id); + + auto const base = reinterpret_cast(m_data.data()); + + return std::string_view{base + offset, size}; + } + + auto common_table_header::length() const noexcept -> kstd::units::bytes + { + using type = decltype(common_table_header_data::length); + + constexpr auto size = sizeof(type); + constexpr auto offset = offsetof(common_table_header_data, length); + + auto const data = std::span{m_data.data() + offset, size}; + auto raw_value = type{}; + + kstd::libc::memcpy(&raw_value, data.data(), size); + + return kstd::units::bytes{raw_value}; + } + + auto common_table_header::oem_id() const noexcept -> std::string_view + { + constexpr auto size = sizeof(common_table_header_data::oem_id); + constexpr auto offset = offsetof(common_table_header_data, oem_id); + + auto const base = reinterpret_cast(m_data.data()); + + return std::string_view{base + offset, size}; + } + + auto common_table_header::oem_table_id() const noexcept -> std::string_view + { + constexpr auto size = sizeof(common_table_header_data::oem_table_id); + constexpr auto offset = offsetof(common_table_header_data, oem_table_id); + + auto const base = reinterpret_cast(m_data.data()); + + return std::string_view{base + offset, size}; + } + + auto common_table_header::oem_revision() const noexcept -> decltype(common_table_header_data::oem_revision) + { + using type = decltype(common_table_header_data::oem_revision); + + constexpr auto size = sizeof(type); + constexpr auto offset = offsetof(common_table_header_data, oem_revision); + + auto const data = std::span{m_data.data() + offset, size}; + auto value = type{}; + + kstd::libc::memcpy(&value, data.data(), size); + + return value; + } + + auto common_table_header::revision() const noexcept -> decltype(common_table_header_data::revision) + { + using type = decltype(common_table_header_data::revision); + + constexpr auto size = sizeof(type); + constexpr auto offset = offsetof(common_table_header_data, revision); + + auto const data = std::span{m_data.data() + offset, size}; + auto value = type{}; + + kstd::libc::memcpy(&value, data.data(), size); + + return value; + } + + auto common_table_header::signature() const noexcept -> std::string_view + { + constexpr auto size = sizeof(common_table_header_data::signature); + constexpr auto offset = offsetof(common_table_header_data, signature); + + auto const base = reinterpret_cast(m_data.data()); + + return std::string_view{base + offset, size}; + } + +} // namespace acpi \ No newline at end of file diff --git a/libs/acpi/acpi/common/table_header.hpp b/libs/acpi/acpi/common/table_header.hpp new file mode 100644 index 0000000..8ecfd0a --- /dev/null +++ b/libs/acpi/acpi/common/table_header.hpp @@ -0,0 +1,57 @@ +#ifndef ACPI_COMMON_TABLE_HEADER_HPP +#define ACPI_COMMON_TABLE_HEADER_HPP + +#include + +#include +#include +#include +#include + +namespace acpi +{ + + //! The size of the common table header as defined in the ACPI specification. + constexpr auto common_table_header_size = 36; + + //! The common header for all ACPI tables, except the FACS. + //! + //! Multibyte fields in the header are not guaranteed to be naturally aligned by the firmware. Therefore, no direct + //! access to multibyte fields is provided. Instead, the provided member functions handle alignment of the multibyte + //! values and thus provide a safe interface to the header fields. + struct common_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::string_view; + + //! 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; + + //! Validate this table's checksum + [[nodiscard]] auto validate() const noexcept -> bool; + + private: + std::array m_data; + }; + +} // namespace acpi + +#endif \ No newline at end of file diff --git a/libs/acpi/acpi/common/table_header.test.cpp b/libs/acpi/acpi/common/table_header.test.cpp new file mode 100644 index 0000000..e43e403 --- /dev/null +++ b/libs/acpi/acpi/common/table_header.test.cpp @@ -0,0 +1,58 @@ +#include + +#include +#include +#include + +SCENARIO("Common table header parsing", "[common_table_header]") +{ + GIVEN("A valid compiled table header") + { + auto data = acpi::test_data::tables::table_header(); + + WHEN("parsing the header") + { + auto header = reinterpret_cast(data.data()); + + THEN("the signature is correct") + { + REQUIRE(header->signature() == "TEST"); + } + + THEN("the revision is correct") + { + REQUIRE(header->revision() == 1); + } + + THEN("the length is correct") + { + REQUIRE(header->length() == kstd::type_size); + } + + THEN("the oem id is correct") + { + REQUIRE(header->oem_id() == "FEMO "); + } + + THEN("the oem table id is correct") + { + REQUIRE(header->oem_table_id() == "HDRTEST "); + } + + THEN("the oem revision is correct") + { + REQUIRE(header->oem_revision() == 1); + } + + THEN("the creator id is correct") + { + REQUIRE(header->creator_id() == "INTL"); + } + + THEN("the creator revision is non-zero") + { + REQUIRE(header->creator_revision() != 0); + } + } + } +} diff --git a/libs/acpi/test_data/table_header.asl b/libs/acpi/test_data/table_header.asl new file mode 100644 index 0000000..8cddc03 --- /dev/null +++ b/libs/acpi/test_data/table_header.asl @@ -0,0 +1,9 @@ +[0004] Signature : "TEST" +[0004] Table Length : 00000000 +[0001] Revision : 01 +[0001] Checksum : 00 +[0006] Oem ID : "FEMO " +[0008] Oem Table ID : "HDRTEST " +[0004] Oem Revision : 00000001 +[0004] Asl Compiler ID : "INTL" +[0004] Asl Compiler Revision : 00000000 diff --git a/libs/acpi/test_data/tables.S b/libs/acpi/test_data/tables.S index f40f070..da9a12f 100644 --- a/libs/acpi/test_data/tables.S +++ b/libs/acpi/test_data/tables.S @@ -11,5 +11,6 @@ TABLE(basic_madt, "basic_madt.aml") TABLE(basic_rsdt, "basic_rsdt.aml") TABLE(basic_rsdp, "basic_rsdp.aml") +TABLE(table_header, "table_header.aml") #undef TABLE diff --git a/libs/acpi/test_data/tables.hpp b/libs/acpi/test_data/tables.hpp index 510cbda..dc39b37 100644 --- a/libs/acpi/test_data/tables.hpp +++ b/libs/acpi/test_data/tables.hpp @@ -18,6 +18,7 @@ namespace acpi::test_data::tables TABLE(basic_madt); TABLE(basic_rsdt); TABLE(basic_rsdp); + TABLE(table_header); } // namespace acpi::test_data::tables -- cgit v1.2.3 From 27c654f3f0a069113b6abb70817cfe2c5096711e Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Wed, 15 Apr 2026 20:46:29 +0200 Subject: acpi: add basic table type --- libs/acpi/CMakeLists.txt | 4 +++- libs/acpi/acpi/acpi.hpp | 10 +++++----- libs/acpi/acpi/checksum.cpp | 19 ------------------- libs/acpi/acpi/checksum.hpp | 20 -------------------- libs/acpi/acpi/common/basic_table.cpp | 26 ++++++++++++++++++++++++++ libs/acpi/acpi/common/basic_table.hpp | 26 ++++++++++++++++++++++++++ libs/acpi/acpi/common/basic_table.test.cpp | 21 +++++++++++++++++++++ libs/acpi/acpi/common/checksum.cpp | 19 +++++++++++++++++++ libs/acpi/acpi/common/checksum.hpp | 20 ++++++++++++++++++++ libs/acpi/acpi/common/table_header.cpp | 16 ++++++++-------- libs/acpi/acpi/common/table_header.hpp | 5 +---- libs/acpi/acpi/common/table_header.test.cpp | 4 ++-- libs/acpi/acpi/pointers.cpp | 2 +- 13 files changed, 132 insertions(+), 60 deletions(-) delete mode 100644 libs/acpi/acpi/checksum.cpp delete mode 100644 libs/acpi/acpi/checksum.hpp create mode 100644 libs/acpi/acpi/common/basic_table.cpp create mode 100644 libs/acpi/acpi/common/basic_table.hpp create mode 100644 libs/acpi/acpi/common/basic_table.test.cpp create mode 100644 libs/acpi/acpi/common/checksum.cpp create mode 100644 libs/acpi/acpi/common/checksum.hpp (limited to 'libs/acpi') diff --git a/libs/acpi/CMakeLists.txt b/libs/acpi/CMakeLists.txt index b9c607d..f850fe4 100644 --- a/libs/acpi/CMakeLists.txt +++ b/libs/acpi/CMakeLists.txt @@ -19,7 +19,8 @@ file(GLOB_RECURSE ACPI_HEADERS ) target_sources("acpi" PRIVATE - "acpi/checksum.cpp" + "acpi/common/basic_table.cpp" + "acpi/common/checksum.cpp" "acpi/common/table_header.cpp" "acpi/madt.cpp" "acpi/pointers.cpp" @@ -60,6 +61,7 @@ if(NOT CMAKE_CROSSCOMPILING) set_source_files_properties("test_data/tables.S" PROPERTIES OBJECT_DEPENDS "${GENERATED_TABLE_BLOBS}") add_executable("acpi_tests" + "acpi/common/basic_table.test.cpp" "acpi/common/table_header.test.cpp" "acpi/madt.test.cpp" "acpi/pointers.test.cpp" diff --git a/libs/acpi/acpi/acpi.hpp b/libs/acpi/acpi/acpi.hpp index fb358cc..47050f2 100644 --- a/libs/acpi/acpi/acpi.hpp +++ b/libs/acpi/acpi/acpi.hpp @@ -1,10 +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 +#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 deleted file mode 100644 index 56275c8..0000000 --- a/libs/acpi/acpi/checksum.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#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 deleted file mode 100644 index a92c242..0000000 --- a/libs/acpi/acpi/checksum.hpp +++ /dev/null @@ -1,20 +0,0 @@ -#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/common/basic_table.cpp b/libs/acpi/acpi/common/basic_table.cpp new file mode 100644 index 0000000..5cec91a --- /dev/null +++ b/libs/acpi/acpi/common/basic_table.cpp @@ -0,0 +1,26 @@ +#include +#include +#include + +#include +#include + +namespace acpi +{ + + auto basic_table::validate_checksum() const noexcept -> bool + { + return acpi::validate_checksum({reinterpret_cast(this), m_header.length().value}); + } + + auto basic_table::as_span() const noexcept -> std::span + { + return {reinterpret_cast(this), m_header.length().value}; + } + + auto basic_table::header() const noexcept -> table_header const & + { + return m_header; + } + +} // namespace acpi \ No newline at end of file diff --git a/libs/acpi/acpi/common/basic_table.hpp b/libs/acpi/acpi/common/basic_table.hpp new file mode 100644 index 0000000..43bf533 --- /dev/null +++ b/libs/acpi/acpi/common/basic_table.hpp @@ -0,0 +1,26 @@ +#ifndef ACPI_COMMON_BASIC_TABLE_HPP +#define ACPI_COMMON_BASIC_TABLE_HPP + +#include + +#include +#include + +namespace acpi +{ + + struct basic_table + { + [[nodiscard]] auto validate_checksum() const noexcept -> bool; + + [[nodiscard]] auto as_span() const noexcept -> std::span; + + [[nodiscard]] auto header() const noexcept -> table_header const &; + + private: + table_header m_header; + }; + +} // namespace acpi + +#endif \ No newline at end of file diff --git a/libs/acpi/acpi/common/basic_table.test.cpp b/libs/acpi/acpi/common/basic_table.test.cpp new file mode 100644 index 0000000..e292b9f --- /dev/null +++ b/libs/acpi/acpi/common/basic_table.test.cpp @@ -0,0 +1,21 @@ +#include +#include +#include + +SCENARIO("Basic table functions", "[basic_table]") +{ + GIVEN("A valid compiled table header") + { + auto data = acpi::test_data::tables::table_header(); + + WHEN("parsing the table") + { + auto table = reinterpret_cast(data.data()); + + THEN("the checksum is valid") + { + REQUIRE(table->validate_checksum()); + } + } + } +} diff --git a/libs/acpi/acpi/common/checksum.cpp b/libs/acpi/acpi/common/checksum.cpp new file mode 100644 index 0000000..09425dd --- /dev/null +++ b/libs/acpi/acpi/common/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/common/checksum.hpp b/libs/acpi/acpi/common/checksum.hpp new file mode 100644 index 0000000..a92c242 --- /dev/null +++ b/libs/acpi/acpi/common/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/common/table_header.cpp b/libs/acpi/acpi/common/table_header.cpp index 17a8219..c69ff5d 100644 --- a/libs/acpi/acpi/common/table_header.cpp +++ b/libs/acpi/acpi/common/table_header.cpp @@ -27,7 +27,7 @@ namespace acpi static_assert(sizeof(common_table_header_data) == common_table_header_size); - auto common_table_header::creator_revision() const noexcept -> decltype(common_table_header_data::creator_revision) + auto table_header::creator_revision() const noexcept -> decltype(common_table_header_data::creator_revision) { using type = decltype(common_table_header_data::creator_revision); @@ -42,7 +42,7 @@ namespace acpi return value; } - auto common_table_header::creator_id() const noexcept -> std::string_view + auto table_header::creator_id() const noexcept -> std::string_view { constexpr auto size = sizeof(common_table_header_data::creator_id); constexpr auto offset = offsetof(common_table_header_data, creator_id); @@ -52,7 +52,7 @@ namespace acpi return std::string_view{base + offset, size}; } - auto common_table_header::length() const noexcept -> kstd::units::bytes + auto table_header::length() const noexcept -> kstd::units::bytes { using type = decltype(common_table_header_data::length); @@ -67,7 +67,7 @@ namespace acpi return kstd::units::bytes{raw_value}; } - auto common_table_header::oem_id() const noexcept -> std::string_view + auto table_header::oem_id() const noexcept -> std::string_view { constexpr auto size = sizeof(common_table_header_data::oem_id); constexpr auto offset = offsetof(common_table_header_data, oem_id); @@ -77,7 +77,7 @@ namespace acpi return std::string_view{base + offset, size}; } - auto common_table_header::oem_table_id() const noexcept -> std::string_view + auto table_header::oem_table_id() const noexcept -> std::string_view { constexpr auto size = sizeof(common_table_header_data::oem_table_id); constexpr auto offset = offsetof(common_table_header_data, oem_table_id); @@ -87,7 +87,7 @@ namespace acpi return std::string_view{base + offset, size}; } - auto common_table_header::oem_revision() const noexcept -> decltype(common_table_header_data::oem_revision) + auto table_header::oem_revision() const noexcept -> decltype(common_table_header_data::oem_revision) { using type = decltype(common_table_header_data::oem_revision); @@ -102,7 +102,7 @@ namespace acpi return value; } - auto common_table_header::revision() const noexcept -> decltype(common_table_header_data::revision) + auto table_header::revision() const noexcept -> decltype(common_table_header_data::revision) { using type = decltype(common_table_header_data::revision); @@ -117,7 +117,7 @@ namespace acpi return value; } - auto common_table_header::signature() const noexcept -> std::string_view + auto table_header::signature() const noexcept -> std::string_view { constexpr auto size = sizeof(common_table_header_data::signature); constexpr auto offset = offsetof(common_table_header_data, signature); diff --git a/libs/acpi/acpi/common/table_header.hpp b/libs/acpi/acpi/common/table_header.hpp index 8ecfd0a..529da81 100644 --- a/libs/acpi/acpi/common/table_header.hpp +++ b/libs/acpi/acpi/common/table_header.hpp @@ -19,7 +19,7 @@ namespace acpi //! Multibyte fields in the header are not guaranteed to be naturally aligned by the firmware. Therefore, no direct //! access to multibyte fields is provided. Instead, the provided member functions handle alignment of the multibyte //! values and thus provide a safe interface to the header fields. - struct common_table_header + struct table_header { //! Get the revision of the utility used to create this table. [[nodiscard]] auto creator_revision() const noexcept -> std::uint32_t; @@ -45,9 +45,6 @@ namespace acpi //! Get the signature of this table. [[nodiscard]] auto signature() const noexcept -> std::string_view; - //! Validate this table's checksum - [[nodiscard]] auto validate() const noexcept -> bool; - private: std::array m_data; }; diff --git a/libs/acpi/acpi/common/table_header.test.cpp b/libs/acpi/acpi/common/table_header.test.cpp index e43e403..d6976b3 100644 --- a/libs/acpi/acpi/common/table_header.test.cpp +++ b/libs/acpi/acpi/common/table_header.test.cpp @@ -12,7 +12,7 @@ SCENARIO("Common table header parsing", "[common_table_header]") WHEN("parsing the header") { - auto header = reinterpret_cast(data.data()); + auto header = reinterpret_cast(data.data()); THEN("the signature is correct") { @@ -26,7 +26,7 @@ SCENARIO("Common table header parsing", "[common_table_header]") THEN("the length is correct") { - REQUIRE(header->length() == kstd::type_size); + REQUIRE(header->length() == kstd::type_size); } THEN("the oem id is correct") diff --git a/libs/acpi/acpi/pointers.cpp b/libs/acpi/acpi/pointers.cpp index 8a8629f..45a42ce 100644 --- a/libs/acpi/acpi/pointers.cpp +++ b/libs/acpi/acpi/pointers.cpp @@ -1,6 +1,6 @@ #include -#include +#include #include #include -- cgit v1.2.3 From 252df23b061b2bf54206da73e41faca600541ccc Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Thu, 16 Apr 2026 09:26:52 +0200 Subject: acpi: introduce VLA table --- libs/acpi/CMakeLists.txt | 3 - libs/acpi/acpi/acpi.hpp | 10 +-- libs/acpi/acpi/common/basic_table.cpp | 26 ------ libs/acpi/acpi/common/basic_table.hpp | 38 +++++++-- libs/acpi/acpi/common/basic_table.test.cpp | 21 ----- libs/acpi/acpi/common/table_header.hpp | 2 + libs/acpi/acpi/common/table_signature.hpp | 17 ++++ libs/acpi/acpi/common/table_type.hpp | 17 ++++ libs/acpi/acpi/common/vla_table.hpp | 115 ++++++++++++++++++++++++++ libs/acpi/acpi/madt.cpp | 104 +++++++++++++++-------- libs/acpi/acpi/madt.hpp | 57 ++++++------- libs/acpi/acpi/madt.test.cpp | 4 +- libs/acpi/acpi/sdt.cpp | 58 ------------- libs/acpi/acpi/sdt.hpp | 127 ----------------------------- libs/acpi/acpi/table_type.hpp | 17 ---- 15 files changed, 287 insertions(+), 329 deletions(-) delete mode 100644 libs/acpi/acpi/common/basic_table.cpp delete mode 100644 libs/acpi/acpi/common/basic_table.test.cpp create mode 100644 libs/acpi/acpi/common/table_signature.hpp create mode 100644 libs/acpi/acpi/common/table_type.hpp create mode 100644 libs/acpi/acpi/common/vla_table.hpp delete mode 100644 libs/acpi/acpi/sdt.cpp delete mode 100644 libs/acpi/acpi/sdt.hpp delete mode 100644 libs/acpi/acpi/table_type.hpp (limited to 'libs/acpi') diff --git a/libs/acpi/CMakeLists.txt b/libs/acpi/CMakeLists.txt index f850fe4..97c351b 100644 --- a/libs/acpi/CMakeLists.txt +++ b/libs/acpi/CMakeLists.txt @@ -19,12 +19,10 @@ file(GLOB_RECURSE ACPI_HEADERS ) target_sources("acpi" PRIVATE - "acpi/common/basic_table.cpp" "acpi/common/checksum.cpp" "acpi/common/table_header.cpp" "acpi/madt.cpp" "acpi/pointers.cpp" - "acpi/sdt.cpp" ) target_sources("acpi" PUBLIC @@ -61,7 +59,6 @@ if(NOT CMAKE_CROSSCOMPILING) set_source_files_properties("test_data/tables.S" PROPERTIES OBJECT_DEPENDS "${GENERATED_TABLE_BLOBS}") add_executable("acpi_tests" - "acpi/common/basic_table.test.cpp" "acpi/common/table_header.test.cpp" "acpi/madt.test.cpp" "acpi/pointers.test.cpp" diff --git a/libs/acpi/acpi/acpi.hpp b/libs/acpi/acpi/acpi.hpp index 47050f2..2962c7a 100644 --- a/libs/acpi/acpi/acpi.hpp +++ b/libs/acpi/acpi/acpi.hpp @@ -1,10 +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 +#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/common/basic_table.cpp b/libs/acpi/acpi/common/basic_table.cpp deleted file mode 100644 index 5cec91a..0000000 --- a/libs/acpi/acpi/common/basic_table.cpp +++ /dev/null @@ -1,26 +0,0 @@ -#include -#include -#include - -#include -#include - -namespace acpi -{ - - auto basic_table::validate_checksum() const noexcept -> bool - { - return acpi::validate_checksum({reinterpret_cast(this), m_header.length().value}); - } - - auto basic_table::as_span() const noexcept -> std::span - { - return {reinterpret_cast(this), m_header.length().value}; - } - - auto basic_table::header() const noexcept -> table_header const & - { - return m_header; - } - -} // namespace acpi \ No newline at end of file diff --git a/libs/acpi/acpi/common/basic_table.hpp b/libs/acpi/acpi/common/basic_table.hpp index 43bf533..b0ead96 100644 --- a/libs/acpi/acpi/common/basic_table.hpp +++ b/libs/acpi/acpi/common/basic_table.hpp @@ -1,21 +1,49 @@ #ifndef ACPI_COMMON_BASIC_TABLE_HPP #define ACPI_COMMON_BASIC_TABLE_HPP +#include #include +#include #include #include +#include namespace acpi { + template struct basic_table { - [[nodiscard]] auto validate_checksum() const noexcept -> bool; - - [[nodiscard]] auto as_span() const noexcept -> std::span; - - [[nodiscard]] auto header() const noexcept -> table_header const &; + [[nodiscard]] auto validate_checksum() const noexcept -> bool + { + return acpi::validate_checksum({reinterpret_cast(this), m_header.length().value}); + } + + [[nodiscard]] auto as_span() const noexcept -> std::span + { + return {reinterpret_cast(this), m_header.length().value}; + } + + [[nodiscard]] auto header() const noexcept -> table_header const & + { + return m_header; + } + + [[nodiscard]] auto length() const noexcept -> std::size_t + { + return m_header.length().value; + } + + [[nodiscard]] auto signature() const noexcept -> std::string_view + { + return m_header.signature(); + } + + [[nodiscard]] auto validate() const noexcept -> bool + { + return signature() == table_signature_v && validate_checksum(); + } private: table_header m_header; diff --git a/libs/acpi/acpi/common/basic_table.test.cpp b/libs/acpi/acpi/common/basic_table.test.cpp deleted file mode 100644 index e292b9f..0000000 --- a/libs/acpi/acpi/common/basic_table.test.cpp +++ /dev/null @@ -1,21 +0,0 @@ -#include -#include -#include - -SCENARIO("Basic table functions", "[basic_table]") -{ - GIVEN("A valid compiled table header") - { - auto data = acpi::test_data::tables::table_header(); - - WHEN("parsing the table") - { - auto table = reinterpret_cast(data.data()); - - THEN("the checksum is valid") - { - REQUIRE(table->validate_checksum()); - } - } - } -} diff --git a/libs/acpi/acpi/common/table_header.hpp b/libs/acpi/acpi/common/table_header.hpp index 529da81..471fed8 100644 --- a/libs/acpi/acpi/common/table_header.hpp +++ b/libs/acpi/acpi/common/table_header.hpp @@ -1,6 +1,8 @@ #ifndef ACPI_COMMON_TABLE_HEADER_HPP #define ACPI_COMMON_TABLE_HEADER_HPP +// IWYU pragma: private, include + #include #include diff --git a/libs/acpi/acpi/common/table_signature.hpp b/libs/acpi/acpi/common/table_signature.hpp new file mode 100644 index 0000000..f0c2d7a --- /dev/null +++ b/libs/acpi/acpi/common/table_signature.hpp @@ -0,0 +1,17 @@ +#ifndef ACPI_COMMON_TABLE_SIGNATURE_HPP +#define ACPI_COMMON_TABLE_SIGNATURE_HPP + +// IWYU pragma: private, include + +namespace acpi +{ + + template + struct table_signature; + + template + constexpr auto table_signature_v = table_signature::value; + +} // namespace acpi + +#endif diff --git a/libs/acpi/acpi/common/table_type.hpp b/libs/acpi/acpi/common/table_type.hpp new file mode 100644 index 0000000..bc427c7 --- /dev/null +++ b/libs/acpi/acpi/common/table_type.hpp @@ -0,0 +1,17 @@ +#ifndef ACPI_COMMON_TABLE_TYPE_HPP +#define ACPI_COMMON_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 diff --git a/libs/acpi/acpi/common/vla_table.hpp b/libs/acpi/acpi/common/vla_table.hpp new file mode 100644 index 0000000..450209c --- /dev/null +++ b/libs/acpi/acpi/common/vla_table.hpp @@ -0,0 +1,115 @@ +#ifndef ACPI_COMMON_VLA_TABLE_HPP +#define ACPI_COMMON_VLA_TABLE_HPP + +#include + +#include +#include + +namespace acpi +{ + + template + struct vla_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 vla_table_iterator() noexcept = default; + + constexpr vla_table_iterator(pointer entry, pointer limit) noexcept + : m_entry{entry} + , m_limit{limit} + {} + + constexpr auto operator++() noexcept -> vla_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 -> vla_table_iterator + { + auto copy = *this; + ++*this; + return copy; + } + + constexpr auto operator*() const noexcept -> reference + { + return *m_entry; + } + + constexpr auto operator->() const noexcept -> pointer + { + return m_entry; + } + + constexpr auto operator==(vla_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{}; + }; + + template + struct vla_table : basic_table + { + using entry_type = EntryType; + using iterator = vla_table_iterator; + using const_iterator = vla_table_iterator; + + [[nodiscard]] auto begin() noexcept -> iterator + { + auto base = std::bit_cast(this); + base += sizeof(TableType); + auto limit = std::bit_cast(this); + limit += this->length(); + return iterator{std::bit_cast(base), std::bit_cast(limit)}; + } + + [[nodiscard]] auto end() noexcept -> iterator + { + return iterator{}; + } + + [[nodiscard]] auto begin() const noexcept -> const_iterator + { + auto base = std::bit_cast(this); + base += sizeof(TableType); + auto limit = std::bit_cast(this); + limit += this->length(); + return const_iterator{std::bit_cast(base), std::bit_cast(limit)}; + } + + [[nodiscard]] auto end() const noexcept -> const_iterator + { + return const_iterator{}; + } + + [[nodiscard]] auto cbegin() const noexcept -> const_iterator + { + return begin(); + } + + [[nodiscard]] auto cend() const noexcept -> const_iterator + { + return end(); + } + }; +} // namespace acpi + +#endif \ No newline at end of file diff --git a/libs/acpi/acpi/madt.cpp b/libs/acpi/acpi/madt.cpp index 6a62f07..c6830ad 100644 --- a/libs/acpi/acpi/madt.cpp +++ b/libs/acpi/acpi/madt.cpp @@ -1,74 +1,112 @@ -#include +#include + #include +#include #include #include +#include namespace acpi { + struct madt_data + { + std::uint32_t local_interrupt_controller_address; + std::uint32_t flags; + }; + + static_assert(sizeof(madt_data) == 8); + auto madt::local_interrupt_controller_address() const noexcept -> std::uintptr_t { - return static_cast(m_local_interrupt_controller_address); + using type = decltype(madt_data::local_interrupt_controller_address); + + constexpr auto size = sizeof(type); + constexpr auto offset = offsetof(madt_data, local_interrupt_controller_address); + + auto const data = std::span{m_data.data() + offset, size}; + auto value = type{}; + + kstd::libc::memcpy(&value, data.data(), size); + + return value; } auto madt::flags() const noexcept -> std::uint32_t { - return m_flags; + using type = decltype(madt_data::flags); + + constexpr auto size = sizeof(type); + constexpr auto offset = offsetof(madt_data, flags); + + auto const data = std::span{m_data.data() + offset, size}; + auto value = type{}; + + kstd::libc::memcpy(&value, data.data(), size); + + return value; } - auto madt::validate() const noexcept -> bool + struct madt_entry_data { - return signature() == madt_table_signature && sdt::validate(); - } + std::uint8_t type; + std::uint8_t length; + }; + + static_assert(sizeof(madt_entry_data) == 2); auto madt_entry::type() const noexcept -> enum type { - return static_cast(m_type); + constexpr auto field_offset = offsetof(madt_entry_data, type); + + return std::bit_cast(*(m_data.data() + field_offset)); } auto madt_entry::length() const noexcept -> std::size_t { - return m_length; - } + constexpr auto field_offset = offsetof(madt_entry_data, length); - auto processor_local_apic::apic_id() const noexcept -> std::uint8_t - { - return m_apic_id; + return static_cast(*(m_data.data() + field_offset)); } - auto processor_local_apic::active_flags() const noexcept -> flags + struct [[gnu::packed]] processor_local_apic_entry_data { - return static_cast(m_flags); - } + std::uint8_t apic_id; + std::uint8_t processor_id; + std::uint32_t flags; + }; - auto processor_local_apic::processor_id() const noexcept -> std::uint32_t - { - return m_processor_id; - } + static_assert(sizeof(processor_local_apic_entry_data) == 6); - auto madt::begin() const noexcept -> iterator + auto processor_local_apic_entry::id() const noexcept -> std::uint8_t { - auto base = reinterpret_cast(this); - base += sizeof(madt); - auto limit = reinterpret_cast(this); - limit += length().value; - return iterator{reinterpret_cast(base), reinterpret_cast(limit)}; - } + constexpr auto field_offset = offsetof(processor_local_apic_entry_data, apic_id); - auto madt::cbegin() const noexcept -> iterator - { - return begin(); + return static_cast(*(m_data.data() + field_offset)); } - auto madt::end() const noexcept -> iterator + auto processor_local_apic_entry::flags() const noexcept -> enum flags { - return {}; + using type = decltype(processor_local_apic_entry_data::flags); + static_assert(sizeof(type) == sizeof(enum flags)); + + constexpr auto size = sizeof(type); + constexpr auto offset = offsetof(processor_local_apic_entry_data, flags); + + auto const data = std::span{m_data.data() + offset, size}; + auto value = type{}; + + kstd::libc::memcpy(&value, data.data(), size); + + return static_cast(value); } - auto madt::cend() const noexcept -> iterator + auto processor_local_apic_entry::processor_id() const noexcept -> std::uint32_t { - return end(); + constexpr auto field_offset = offsetof(processor_local_apic_entry_data, processor_id); + + return static_cast(*(m_data.data() + field_offset)); } } // namespace acpi diff --git a/libs/acpi/acpi/madt.hpp b/libs/acpi/acpi/madt.hpp index 8b75f58..8307826 100644 --- a/libs/acpi/acpi/madt.hpp +++ b/libs/acpi/acpi/madt.hpp @@ -7,9 +7,11 @@ #include #include -#include -#include +#include +#include +#include +#include #include #include #include @@ -18,7 +20,19 @@ namespace acpi { - struct [[gnu::packed]] madt_entry + template<> + struct table_signature + { + constexpr char static const value[] = "APIC"; // NOLINT + }; + + template<> + struct table_type> + { + using type = struct madt; + }; + + struct madt_entry { //! The type of an MADT entry. enum struct type : std::uint8_t @@ -53,26 +67,16 @@ namespace acpi } private: - std::uint8_t m_type; - std::uint8_t m_length; + std::array m_data{}; }; //! The Multiple APIC Description Table (MADT) - struct [[gnu::packed]] madt : sdt + struct madt : vla_table { - using iterator = sdt_iterator; - using const_iterator = iterator; - //! Get the physical address of the local interrupt controllers described by this entry. [[nodiscard]] auto local_interrupt_controller_address() const noexcept -> std::uintptr_t; [[nodiscard]] auto flags() const noexcept -> std::uint32_t; - [[nodiscard]] auto validate() const noexcept -> bool; - - [[nodiscard]] auto begin() const noexcept -> iterator; - [[nodiscard]] auto cbegin() const noexcept -> iterator; - [[nodiscard]] auto end() const noexcept -> iterator; - [[nodiscard]] auto cend() const noexcept -> iterator; template [[nodiscard]] auto only() const noexcept @@ -82,11 +86,10 @@ namespace acpi } private: - std::uint32_t m_local_interrupt_controller_address; - std::uint32_t m_flags; + std::array m_data{}; }; - struct [[gnu::packed]] processor_local_apic : madt_entry + struct processor_local_apic_entry : madt_entry { constexpr auto static this_type = type::processor_local_apic; @@ -96,28 +99,18 @@ namespace acpi online_capable = 2, }; - [[nodiscard]] auto apic_id() const noexcept -> std::uint8_t; - [[nodiscard]] auto active_flags() const noexcept -> flags; + [[nodiscard]] auto id() const noexcept -> std::uint8_t; + [[nodiscard]] auto 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; + std::array m_data{}; }; } // namespace acpi template<> -struct kstd::ext::is_bitfield_enum : std::true_type +struct kstd::ext::is_bitfield_enum : std::true_type { }; diff --git a/libs/acpi/acpi/madt.test.cpp b/libs/acpi/acpi/madt.test.cpp index 8926192..899a377 100644 --- a/libs/acpi/acpi/madt.test.cpp +++ b/libs/acpi/acpi/madt.test.cpp @@ -38,7 +38,7 @@ SCENARIO("MADT parsing", "[madt]") THEN("the length is sizeof(madt) + sizeof(processor_local_apic)") { - REQUIRE(madt->length() == kstd::type_size + kstd::type_size); + REQUIRE(madt->length() == sizeof(acpi::madt) + sizeof(acpi::processor_local_apic_entry)); } THEN("the first entry has type processor_local_apic") @@ -48,7 +48,7 @@ SCENARIO("MADT parsing", "[madt]") THEN("`only` can be used to get a view of all processor_local_apic entries") { - REQUIRE(std::ranges::distance(madt->only()) == 1); + REQUIRE(std::ranges::distance(madt->only()) == 1); } } } diff --git a/libs/acpi/acpi/sdt.cpp b/libs/acpi/acpi/sdt.cpp deleted file mode 100644 index 6c6cb47..0000000 --- a/libs/acpi/acpi/sdt.cpp +++ /dev/null @@ -1,58 +0,0 @@ -#include - -#include -#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()}; - } - - auto sdt::validate() const noexcept -> bool - { - return acpi::validate_checksum({reinterpret_cast(this), length().value}); - } - -} // namespace acpi diff --git a/libs/acpi/acpi/sdt.hpp b/libs/acpi/acpi/sdt.hpp deleted file mode 100644 index 72b3896..0000000 --- a/libs/acpi/acpi/sdt.hpp +++ /dev/null @@ -1,127 +0,0 @@ -#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->() const noexcept -> pointer - { - 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; - - //! Valide this table's checksum - [[nodiscard]] auto validate() const noexcept -> bool; - - 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 deleted file mode 100644 index 7fdd7e3..0000000 --- a/libs/acpi/acpi/table_type.hpp +++ /dev/null @@ -1,17 +0,0 @@ -#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 From 89f1c730fb9daf4a5da0748934ca5befd90eb731 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Thu, 16 Apr 2026 09:28:16 +0200 Subject: acpi: move madt to data --- libs/acpi/CMakeLists.txt | 4 +- libs/acpi/acpi/acpi.hpp | 2 +- libs/acpi/acpi/data/madt.cpp | 112 ++++++++++++++++++++++++++++++++++++ libs/acpi/acpi/data/madt.hpp | 117 ++++++++++++++++++++++++++++++++++++++ libs/acpi/acpi/data/madt.test.cpp | 55 ++++++++++++++++++ libs/acpi/acpi/madt.cpp | 112 ------------------------------------ libs/acpi/acpi/madt.hpp | 117 -------------------------------------- libs/acpi/acpi/madt.test.cpp | 55 ------------------ 8 files changed, 287 insertions(+), 287 deletions(-) create mode 100644 libs/acpi/acpi/data/madt.cpp create mode 100644 libs/acpi/acpi/data/madt.hpp create mode 100644 libs/acpi/acpi/data/madt.test.cpp delete mode 100644 libs/acpi/acpi/madt.cpp delete mode 100644 libs/acpi/acpi/madt.hpp delete mode 100644 libs/acpi/acpi/madt.test.cpp (limited to 'libs/acpi') diff --git a/libs/acpi/CMakeLists.txt b/libs/acpi/CMakeLists.txt index 97c351b..f6e484c 100644 --- a/libs/acpi/CMakeLists.txt +++ b/libs/acpi/CMakeLists.txt @@ -21,7 +21,7 @@ file(GLOB_RECURSE ACPI_HEADERS target_sources("acpi" PRIVATE "acpi/common/checksum.cpp" "acpi/common/table_header.cpp" - "acpi/madt.cpp" + "acpi/data/madt.cpp" "acpi/pointers.cpp" ) @@ -60,7 +60,7 @@ if(NOT CMAKE_CROSSCOMPILING) add_executable("acpi_tests" "acpi/common/table_header.test.cpp" - "acpi/madt.test.cpp" + "acpi/data/madt.test.cpp" "acpi/pointers.test.cpp" "test_data/tables.S" diff --git a/libs/acpi/acpi/acpi.hpp b/libs/acpi/acpi/acpi.hpp index 2962c7a..4cfcede 100644 --- a/libs/acpi/acpi/acpi.hpp +++ b/libs/acpi/acpi/acpi.hpp @@ -4,7 +4,7 @@ #include // IWYU pragma: export #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/data/madt.cpp b/libs/acpi/acpi/data/madt.cpp new file mode 100644 index 0000000..a8d4741 --- /dev/null +++ b/libs/acpi/acpi/data/madt.cpp @@ -0,0 +1,112 @@ +#include + +#include + +#include +#include +#include +#include + +namespace acpi +{ + + struct madt_data + { + std::uint32_t local_interrupt_controller_address; + std::uint32_t flags; + }; + + static_assert(sizeof(madt_data) == 8); + + auto madt::local_interrupt_controller_address() const noexcept -> std::uintptr_t + { + using type = decltype(madt_data::local_interrupt_controller_address); + + constexpr auto size = sizeof(type); + constexpr auto offset = offsetof(madt_data, local_interrupt_controller_address); + + auto const data = std::span{m_data.data() + offset, size}; + auto value = type{}; + + kstd::libc::memcpy(&value, data.data(), size); + + return value; + } + + auto madt::flags() const noexcept -> std::uint32_t + { + using type = decltype(madt_data::flags); + + constexpr auto size = sizeof(type); + constexpr auto offset = offsetof(madt_data, flags); + + auto const data = std::span{m_data.data() + offset, size}; + auto value = type{}; + + kstd::libc::memcpy(&value, data.data(), size); + + return value; + } + + struct madt_entry_data + { + std::uint8_t type; + std::uint8_t length; + }; + + static_assert(sizeof(madt_entry_data) == 2); + + auto madt_entry::type() const noexcept -> enum type + { + constexpr auto field_offset = offsetof(madt_entry_data, type); + + return std::bit_cast(*(m_data.data() + field_offset)); + } + + auto madt_entry::length() const noexcept -> std::size_t + { + constexpr auto field_offset = offsetof(madt_entry_data, length); + + return static_cast(*(m_data.data() + field_offset)); + } + + struct [[gnu::packed]] processor_local_apic_entry_data + { + std::uint8_t apic_id; + std::uint8_t processor_id; + std::uint32_t flags; + }; + + static_assert(sizeof(processor_local_apic_entry_data) == 6); + + auto processor_local_apic_entry::id() const noexcept -> std::uint8_t + { + constexpr auto field_offset = offsetof(processor_local_apic_entry_data, apic_id); + + return static_cast(*(m_data.data() + field_offset)); + } + + auto processor_local_apic_entry::flags() const noexcept -> enum flags + { + using type = decltype(processor_local_apic_entry_data::flags); + static_assert(sizeof(type) == sizeof(enum flags)); + + constexpr auto size = sizeof(type); + constexpr auto offset = offsetof(processor_local_apic_entry_data, flags); + + auto const data = std::span{m_data.data() + offset, size}; + auto value = type{}; + + kstd::libc::memcpy(&value, data.data(), size); + + return static_cast(value); + } + + auto processor_local_apic_entry::processor_id() const noexcept -> std::uint32_t + { + constexpr auto field_offset = offsetof(processor_local_apic_entry_data, processor_id); + + return static_cast(*(m_data.data() + field_offset)); + } + +} // namespace acpi diff --git a/libs/acpi/acpi/data/madt.hpp b/libs/acpi/acpi/data/madt.hpp new file mode 100644 index 0000000..8307826 --- /dev/null +++ b/libs/acpi/acpi/data/madt.hpp @@ -0,0 +1,117 @@ +#ifndef ACPI_ACPI_MADT_HPP +#define ACPI_ACPI_MADT_HPP + +// IWYU pragma: private, include + +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +namespace acpi +{ + + template<> + struct table_signature + { + constexpr char static const value[] = "APIC"; // NOLINT + }; + + template<> + struct table_type> + { + using type = struct madt; + }; + + struct madt_entry + { + //! The type of an MADT entry. + enum struct type : 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, + }; + + //! Get the type of this entry. + [[nodiscard]] auto type() const noexcept -> enum type; + + //! Get the length of this entry. + [[nodiscard]] auto length() const noexcept -> std::size_t; + + //! Cast this entry to the given concrete entry type. + //! + //! @warning This function will terminate execution if the desired target type does not match up with this entry's + //! actual type. + template + [[nodiscard]] auto as() const -> EntryType const & + { + if (type() != EntryType::this_type) + { + kstd::os::panic("Invalid cast"); + } + return reinterpret_cast(*this); + } + + private: + std::array m_data{}; + }; + + //! The Multiple APIC Description Table (MADT) + struct madt : vla_table + { + //! Get the physical address of the local interrupt controllers described by this entry. + [[nodiscard]] auto local_interrupt_controller_address() const noexcept -> std::uintptr_t; + + [[nodiscard]] auto flags() const noexcept -> std::uint32_t; + + template + [[nodiscard]] auto only() const noexcept + { + return *this | std::views::filter([](auto const & e) { return e.type() == EntryType::this_type; }) | + std::views::transform([](auto const & e) { return e.template as(); }); + } + + private: + std::array m_data{}; + }; + + struct processor_local_apic_entry : madt_entry + { + constexpr auto static this_type = type::processor_local_apic; + + enum struct flags : std::uint32_t + { + processor_enabled = 1, + online_capable = 2, + }; + + [[nodiscard]] auto id() const noexcept -> std::uint8_t; + [[nodiscard]] auto flags() const noexcept -> flags; + [[nodiscard]] auto processor_id() const noexcept -> std::uint32_t; + + private: + std::array m_data{}; + }; + +} // namespace acpi + +template<> +struct kstd::ext::is_bitfield_enum : std::true_type +{ +}; + +#endif diff --git a/libs/acpi/acpi/data/madt.test.cpp b/libs/acpi/acpi/data/madt.test.cpp new file mode 100644 index 0000000..2b74d4c --- /dev/null +++ b/libs/acpi/acpi/data/madt.test.cpp @@ -0,0 +1,55 @@ +#include + +#include +#include +#include + +#include + +SCENARIO("MADT parsing", "[madt]") +{ + GIVEN("The basic compiled MADT containing a single LAPIC entry and the default x86 LAPIC address") + { + auto data = acpi::test_data::tables::basic_madt(); + + WHEN("parsing the table") + { + auto madt = reinterpret_cast(data.data()); + + THEN("the signature is correct") + { + REQUIRE(madt->signature() == "APIC"); + } + + THEN("validate returns true") + { + REQUIRE(madt->validate()); + } + + THEN("there is a single entry in the table") + { + REQUIRE(std::distance(madt->begin(), madt->end()) == 1); + } + + THEN("the LAPIC address is 0xfee00000") + { + REQUIRE(madt->local_interrupt_controller_address() == 0xfee0'0000); + } + + THEN("the length is sizeof(madt) + sizeof(processor_local_apic)") + { + REQUIRE(madt->length() == sizeof(acpi::madt) + sizeof(acpi::processor_local_apic_entry)); + } + + THEN("the first entry has type processor_local_apic") + { + REQUIRE(madt->cbegin()->type() == acpi::madt_entry::type::processor_local_apic); + } + + THEN("`only` can be used to get a view of all processor_local_apic entries") + { + REQUIRE(std::ranges::distance(madt->only()) == 1); + } + } + } +} diff --git a/libs/acpi/acpi/madt.cpp b/libs/acpi/acpi/madt.cpp deleted file mode 100644 index c6830ad..0000000 --- a/libs/acpi/acpi/madt.cpp +++ /dev/null @@ -1,112 +0,0 @@ -#include - -#include - -#include -#include -#include -#include - -namespace acpi -{ - - struct madt_data - { - std::uint32_t local_interrupt_controller_address; - std::uint32_t flags; - }; - - static_assert(sizeof(madt_data) == 8); - - auto madt::local_interrupt_controller_address() const noexcept -> std::uintptr_t - { - using type = decltype(madt_data::local_interrupt_controller_address); - - constexpr auto size = sizeof(type); - constexpr auto offset = offsetof(madt_data, local_interrupt_controller_address); - - auto const data = std::span{m_data.data() + offset, size}; - auto value = type{}; - - kstd::libc::memcpy(&value, data.data(), size); - - return value; - } - - auto madt::flags() const noexcept -> std::uint32_t - { - using type = decltype(madt_data::flags); - - constexpr auto size = sizeof(type); - constexpr auto offset = offsetof(madt_data, flags); - - auto const data = std::span{m_data.data() + offset, size}; - auto value = type{}; - - kstd::libc::memcpy(&value, data.data(), size); - - return value; - } - - struct madt_entry_data - { - std::uint8_t type; - std::uint8_t length; - }; - - static_assert(sizeof(madt_entry_data) == 2); - - auto madt_entry::type() const noexcept -> enum type - { - constexpr auto field_offset = offsetof(madt_entry_data, type); - - return std::bit_cast(*(m_data.data() + field_offset)); - } - - auto madt_entry::length() const noexcept -> std::size_t - { - constexpr auto field_offset = offsetof(madt_entry_data, length); - - return static_cast(*(m_data.data() + field_offset)); - } - - struct [[gnu::packed]] processor_local_apic_entry_data - { - std::uint8_t apic_id; - std::uint8_t processor_id; - std::uint32_t flags; - }; - - static_assert(sizeof(processor_local_apic_entry_data) == 6); - - auto processor_local_apic_entry::id() const noexcept -> std::uint8_t - { - constexpr auto field_offset = offsetof(processor_local_apic_entry_data, apic_id); - - return static_cast(*(m_data.data() + field_offset)); - } - - auto processor_local_apic_entry::flags() const noexcept -> enum flags - { - using type = decltype(processor_local_apic_entry_data::flags); - static_assert(sizeof(type) == sizeof(enum flags)); - - constexpr auto size = sizeof(type); - constexpr auto offset = offsetof(processor_local_apic_entry_data, flags); - - auto const data = std::span{m_data.data() + offset, size}; - auto value = type{}; - - kstd::libc::memcpy(&value, data.data(), size); - - return static_cast(value); - } - - auto processor_local_apic_entry::processor_id() const noexcept -> std::uint32_t - { - constexpr auto field_offset = offsetof(processor_local_apic_entry_data, processor_id); - - return static_cast(*(m_data.data() + field_offset)); - } - -} // namespace acpi diff --git a/libs/acpi/acpi/madt.hpp b/libs/acpi/acpi/madt.hpp deleted file mode 100644 index 8307826..0000000 --- a/libs/acpi/acpi/madt.hpp +++ /dev/null @@ -1,117 +0,0 @@ -#ifndef ACPI_ACPI_MADT_HPP -#define ACPI_ACPI_MADT_HPP - -// IWYU pragma: private, include - -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include -#include - -namespace acpi -{ - - template<> - struct table_signature - { - constexpr char static const value[] = "APIC"; // NOLINT - }; - - template<> - struct table_type> - { - using type = struct madt; - }; - - struct madt_entry - { - //! The type of an MADT entry. - enum struct type : 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, - }; - - //! Get the type of this entry. - [[nodiscard]] auto type() const noexcept -> enum type; - - //! Get the length of this entry. - [[nodiscard]] auto length() const noexcept -> std::size_t; - - //! Cast this entry to the given concrete entry type. - //! - //! @warning This function will terminate execution if the desired target type does not match up with this entry's - //! actual type. - template - [[nodiscard]] auto as() const -> EntryType const & - { - if (type() != EntryType::this_type) - { - kstd::os::panic("Invalid cast"); - } - return reinterpret_cast(*this); - } - - private: - std::array m_data{}; - }; - - //! The Multiple APIC Description Table (MADT) - struct madt : vla_table - { - //! Get the physical address of the local interrupt controllers described by this entry. - [[nodiscard]] auto local_interrupt_controller_address() const noexcept -> std::uintptr_t; - - [[nodiscard]] auto flags() const noexcept -> std::uint32_t; - - template - [[nodiscard]] auto only() const noexcept - { - return *this | std::views::filter([](auto const & e) { return e.type() == EntryType::this_type; }) | - std::views::transform([](auto const & e) { return e.template as(); }); - } - - private: - std::array m_data{}; - }; - - struct processor_local_apic_entry : madt_entry - { - constexpr auto static this_type = type::processor_local_apic; - - enum struct flags : std::uint32_t - { - processor_enabled = 1, - online_capable = 2, - }; - - [[nodiscard]] auto id() const noexcept -> std::uint8_t; - [[nodiscard]] auto flags() const noexcept -> flags; - [[nodiscard]] auto processor_id() const noexcept -> std::uint32_t; - - private: - std::array m_data{}; - }; - -} // namespace acpi - -template<> -struct kstd::ext::is_bitfield_enum : std::true_type -{ -}; - -#endif diff --git a/libs/acpi/acpi/madt.test.cpp b/libs/acpi/acpi/madt.test.cpp deleted file mode 100644 index 899a377..0000000 --- a/libs/acpi/acpi/madt.test.cpp +++ /dev/null @@ -1,55 +0,0 @@ -#include - -#include -#include -#include - -#include - -SCENARIO("MADT parsing", "[madt]") -{ - GIVEN("The basic compiled MADT containing a single LAPIC entry and the default x86 LAPIC address") - { - auto data = acpi::test_data::tables::basic_madt(); - - WHEN("parsing the table") - { - auto madt = reinterpret_cast(data.data()); - - THEN("the signature is correct") - { - REQUIRE(madt->signature() == "APIC"); - } - - THEN("validate returns true") - { - REQUIRE(madt->validate()); - } - - THEN("there is a single entry in the table") - { - REQUIRE(std::distance(madt->begin(), madt->end()) == 1); - } - - THEN("the LAPIC address is 0xfee00000") - { - REQUIRE(madt->local_interrupt_controller_address() == 0xfee0'0000); - } - - THEN("the length is sizeof(madt) + sizeof(processor_local_apic)") - { - REQUIRE(madt->length() == sizeof(acpi::madt) + sizeof(acpi::processor_local_apic_entry)); - } - - THEN("the first entry has type processor_local_apic") - { - REQUIRE(madt->cbegin()->type() == acpi::madt_entry::type::processor_local_apic); - } - - THEN("`only` can be used to get a view of all processor_local_apic entries") - { - REQUIRE(std::ranges::distance(madt->only()) == 1); - } - } - } -} -- cgit v1.2.3 From b31c47b32d91b0b85245ed30f1751cd5cbc397cf Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Thu, 16 Apr 2026 09:37:41 +0200 Subject: acpi: add rsdt type --- libs/acpi/CMakeLists.txt | 2 ++ libs/acpi/acpi/data/rsdt.cpp | 37 +++++++++++++++++++++++++++++++ libs/acpi/acpi/data/rsdt.hpp | 42 +++++++++++++++++++++++++++++++++++ libs/acpi/acpi/data/rsdt.test.cpp | 46 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 127 insertions(+) create mode 100644 libs/acpi/acpi/data/rsdt.cpp create mode 100644 libs/acpi/acpi/data/rsdt.hpp create mode 100644 libs/acpi/acpi/data/rsdt.test.cpp (limited to 'libs/acpi') diff --git a/libs/acpi/CMakeLists.txt b/libs/acpi/CMakeLists.txt index f6e484c..833dcea 100644 --- a/libs/acpi/CMakeLists.txt +++ b/libs/acpi/CMakeLists.txt @@ -22,6 +22,7 @@ target_sources("acpi" PRIVATE "acpi/common/checksum.cpp" "acpi/common/table_header.cpp" "acpi/data/madt.cpp" + "acpi/data/rsdt.cpp" "acpi/pointers.cpp" ) @@ -61,6 +62,7 @@ if(NOT CMAKE_CROSSCOMPILING) add_executable("acpi_tests" "acpi/common/table_header.test.cpp" "acpi/data/madt.test.cpp" + "acpi/data/rsdt.test.cpp" "acpi/pointers.test.cpp" "test_data/tables.S" diff --git a/libs/acpi/acpi/data/rsdt.cpp b/libs/acpi/acpi/data/rsdt.cpp new file mode 100644 index 0000000..8e20b6c --- /dev/null +++ b/libs/acpi/acpi/data/rsdt.cpp @@ -0,0 +1,37 @@ +#include + +#include +#include + +#include +#include + +namespace acpi +{ + + struct rsdt_entry_data + { + std::uint32_t address; + }; + + [[nodiscard]] auto rsdt_entry::address() const noexcept -> table_header * + { + using type = decltype(rsdt_entry_data::address); + + constexpr auto size = sizeof(type); + constexpr auto offset = offsetof(rsdt_entry_data, address); + + auto const data = std::span{m_data.data() + offset, size}; + auto value = type{}; + + kstd::libc::memcpy(&value, data.data(), size); + + return reinterpret_cast(static_cast(value)); + } + + [[nodiscard]] auto rsdt_entry::length() const noexcept -> std::size_t + { + return sizeof(m_data); + } + +} // namespace acpi \ No newline at end of file diff --git a/libs/acpi/acpi/data/rsdt.hpp b/libs/acpi/acpi/data/rsdt.hpp new file mode 100644 index 0000000..b43f066 --- /dev/null +++ b/libs/acpi/acpi/data/rsdt.hpp @@ -0,0 +1,42 @@ +#ifndef ACPI_DATA_RSDT_HPP +#define ACPI_DATA_RSDT_HPP + +#include +#include +#include +#include + +#include +#include + +namespace acpi +{ + + template<> + struct table_signature + { + constexpr char static const value[] = "RSDT"; // NOLINT + }; + + template<> + struct table_type> + { + using type = struct rsdt; + }; + + struct rsdt_entry + { + [[nodiscard]] auto address() const noexcept -> table_header *; + [[nodiscard]] auto length() const noexcept -> std::size_t; + + private: + std::array m_data{}; + }; + + struct rsdt : vla_table + { + }; + +} // namespace acpi + +#endif \ No newline at end of file diff --git a/libs/acpi/acpi/data/rsdt.test.cpp b/libs/acpi/acpi/data/rsdt.test.cpp new file mode 100644 index 0000000..e1bd1df --- /dev/null +++ b/libs/acpi/acpi/data/rsdt.test.cpp @@ -0,0 +1,46 @@ +#include + +#include +#include +#include +#include + +#include + +SCENARIO("RSDT parsing", "[rsdt]") +{ + GIVEN("The basic compiled RSDT containing 8 table pointers") + { + auto data = acpi::test_data::tables::basic_rsdt(); + + WHEN("parsing the table") + { + auto rsdt = reinterpret_cast(data.data()); + + THEN("the signature is correct") + { + REQUIRE(rsdt->signature() == "RSDT"); + } + + THEN("validate returns true") + { + REQUIRE(rsdt->validate()); + } + + THEN("there are 8 entries in the table") + { + REQUIRE(std::distance(rsdt->begin(), rsdt->end()) == 8); + } + + THEN("the first entry has address 0x10") + { + REQUIRE(rsdt->cbegin()->address() == reinterpret_cast(0x10)); + } + + THEN("the length is sizeof(rsdt) + 8 * sizeof(rsdt_entry)") + { + REQUIRE(rsdt->length() == sizeof(acpi::rsdt) + 8 * sizeof(acpi::rsdt_entry)); + } + } + } +} -- cgit v1.2.3 From 28cae58fe117e5fcfc46fd6378e19387cd73b2fe Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Thu, 16 Apr 2026 09:40:12 +0200 Subject: acpi: derive basic table from table header --- libs/acpi/acpi/acpi.hpp | 1 + libs/acpi/acpi/common/basic_table.hpp | 25 +++---------------------- libs/acpi/acpi/common/vla_table.hpp | 4 ++-- libs/acpi/acpi/data/madt.test.cpp | 2 +- libs/acpi/acpi/data/rsdt.cpp | 1 + libs/acpi/acpi/data/rsdt.hpp | 1 - libs/acpi/acpi/data/rsdt.test.cpp | 2 +- 7 files changed, 9 insertions(+), 27 deletions(-) (limited to 'libs/acpi') diff --git a/libs/acpi/acpi/acpi.hpp b/libs/acpi/acpi/acpi.hpp index 4cfcede..385ddc9 100644 --- a/libs/acpi/acpi/acpi.hpp +++ b/libs/acpi/acpi/acpi.hpp @@ -5,6 +5,7 @@ #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/common/basic_table.hpp b/libs/acpi/acpi/common/basic_table.hpp index b0ead96..33f23d5 100644 --- a/libs/acpi/acpi/common/basic_table.hpp +++ b/libs/acpi/acpi/common/basic_table.hpp @@ -7,46 +7,27 @@ #include #include -#include namespace acpi { template - struct basic_table + struct basic_table : table_header { [[nodiscard]] auto validate_checksum() const noexcept -> bool { - return acpi::validate_checksum({reinterpret_cast(this), m_header.length().value}); + return acpi::validate_checksum(as_span()); } [[nodiscard]] auto as_span() const noexcept -> std::span { - return {reinterpret_cast(this), m_header.length().value}; - } - - [[nodiscard]] auto header() const noexcept -> table_header const & - { - return m_header; - } - - [[nodiscard]] auto length() const noexcept -> std::size_t - { - return m_header.length().value; - } - - [[nodiscard]] auto signature() const noexcept -> std::string_view - { - return m_header.signature(); + return {reinterpret_cast(this), length().value}; } [[nodiscard]] auto validate() const noexcept -> bool { return signature() == table_signature_v && validate_checksum(); } - - private: - table_header m_header; }; } // namespace acpi diff --git a/libs/acpi/acpi/common/vla_table.hpp b/libs/acpi/acpi/common/vla_table.hpp index 450209c..a65a28e 100644 --- a/libs/acpi/acpi/common/vla_table.hpp +++ b/libs/acpi/acpi/common/vla_table.hpp @@ -77,7 +77,7 @@ namespace acpi auto base = std::bit_cast(this); base += sizeof(TableType); auto limit = std::bit_cast(this); - limit += this->length(); + limit += this->length().value; return iterator{std::bit_cast(base), std::bit_cast(limit)}; } @@ -91,7 +91,7 @@ namespace acpi auto base = std::bit_cast(this); base += sizeof(TableType); auto limit = std::bit_cast(this); - limit += this->length(); + limit += this->length().value; return const_iterator{std::bit_cast(base), std::bit_cast(limit)}; } diff --git a/libs/acpi/acpi/data/madt.test.cpp b/libs/acpi/acpi/data/madt.test.cpp index 2b74d4c..6795499 100644 --- a/libs/acpi/acpi/data/madt.test.cpp +++ b/libs/acpi/acpi/data/madt.test.cpp @@ -38,7 +38,7 @@ SCENARIO("MADT parsing", "[madt]") THEN("the length is sizeof(madt) + sizeof(processor_local_apic)") { - REQUIRE(madt->length() == sizeof(acpi::madt) + sizeof(acpi::processor_local_apic_entry)); + REQUIRE(madt->length().value == sizeof(acpi::madt) + sizeof(acpi::processor_local_apic_entry)); } THEN("the first entry has type processor_local_apic") diff --git a/libs/acpi/acpi/data/rsdt.cpp b/libs/acpi/acpi/data/rsdt.cpp index 8e20b6c..fe108c7 100644 --- a/libs/acpi/acpi/data/rsdt.cpp +++ b/libs/acpi/acpi/data/rsdt.cpp @@ -5,6 +5,7 @@ #include #include +#include namespace acpi { diff --git a/libs/acpi/acpi/data/rsdt.hpp b/libs/acpi/acpi/data/rsdt.hpp index b43f066..88c5fd1 100644 --- a/libs/acpi/acpi/data/rsdt.hpp +++ b/libs/acpi/acpi/data/rsdt.hpp @@ -1,7 +1,6 @@ #ifndef ACPI_DATA_RSDT_HPP #define ACPI_DATA_RSDT_HPP -#include #include #include #include diff --git a/libs/acpi/acpi/data/rsdt.test.cpp b/libs/acpi/acpi/data/rsdt.test.cpp index e1bd1df..937dce0 100644 --- a/libs/acpi/acpi/data/rsdt.test.cpp +++ b/libs/acpi/acpi/data/rsdt.test.cpp @@ -39,7 +39,7 @@ SCENARIO("RSDT parsing", "[rsdt]") THEN("the length is sizeof(rsdt) + 8 * sizeof(rsdt_entry)") { - REQUIRE(rsdt->length() == sizeof(acpi::rsdt) + 8 * sizeof(acpi::rsdt_entry)); + REQUIRE(rsdt->length().value == sizeof(acpi::rsdt) + 8 * sizeof(acpi::rsdt_entry)); } } } -- cgit v1.2.3 From 776ab2749d5af0a34fd2aa6103a377ddc04d4c53 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Thu, 16 Apr 2026 10:03:35 +0200 Subject: acpi: introduce XSDT type --- libs/acpi/CMakeLists.txt | 3 +++ libs/acpi/acpi/acpi.hpp | 1 + libs/acpi/acpi/data/rsdt.hpp | 1 + libs/acpi/acpi/data/xsdt.cpp | 38 +++++++++++++++++++++++++++++++ libs/acpi/acpi/data/xsdt.hpp | 42 ++++++++++++++++++++++++++++++++++ libs/acpi/acpi/data/xsdt.test.cpp | 46 ++++++++++++++++++++++++++++++++++++++ libs/acpi/test_data/basic_xsdt.asl | 26 +++++++++++++++++++++ libs/acpi/test_data/tables.S | 1 + libs/acpi/test_data/tables.hpp | 1 + 9 files changed, 159 insertions(+) create mode 100644 libs/acpi/acpi/data/xsdt.cpp create mode 100644 libs/acpi/acpi/data/xsdt.hpp create mode 100644 libs/acpi/acpi/data/xsdt.test.cpp create mode 100644 libs/acpi/test_data/basic_xsdt.asl (limited to 'libs/acpi') diff --git a/libs/acpi/CMakeLists.txt b/libs/acpi/CMakeLists.txt index 833dcea..55d5b54 100644 --- a/libs/acpi/CMakeLists.txt +++ b/libs/acpi/CMakeLists.txt @@ -23,6 +23,7 @@ target_sources("acpi" PRIVATE "acpi/common/table_header.cpp" "acpi/data/madt.cpp" "acpi/data/rsdt.cpp" + "acpi/data/xsdt.cpp" "acpi/pointers.cpp" ) @@ -44,6 +45,7 @@ if(NOT CMAKE_CROSSCOMPILING) "basic_madt" "basic_rsdt" "basic_rsdp" + "basic_xsdt" "table_header" ) @@ -63,6 +65,7 @@ if(NOT CMAKE_CROSSCOMPILING) "acpi/common/table_header.test.cpp" "acpi/data/madt.test.cpp" "acpi/data/rsdt.test.cpp" + "acpi/data/xsdt.test.cpp" "acpi/pointers.test.cpp" "test_data/tables.S" diff --git a/libs/acpi/acpi/acpi.hpp b/libs/acpi/acpi/acpi.hpp index 385ddc9..0da44a8 100644 --- a/libs/acpi/acpi/acpi.hpp +++ b/libs/acpi/acpi/acpi.hpp @@ -6,6 +6,7 @@ #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/data/rsdt.hpp b/libs/acpi/acpi/data/rsdt.hpp index 88c5fd1..a661187 100644 --- a/libs/acpi/acpi/data/rsdt.hpp +++ b/libs/acpi/acpi/data/rsdt.hpp @@ -1,6 +1,7 @@ #ifndef ACPI_DATA_RSDT_HPP #define ACPI_DATA_RSDT_HPP +#include #include #include #include diff --git a/libs/acpi/acpi/data/xsdt.cpp b/libs/acpi/acpi/data/xsdt.cpp new file mode 100644 index 0000000..b4202b8 --- /dev/null +++ b/libs/acpi/acpi/data/xsdt.cpp @@ -0,0 +1,38 @@ +#include + +#include +#include + +#include +#include +#include + +namespace acpi +{ + + struct xsdt_entry_data + { + std::uint64_t address; + }; + + [[nodiscard]] auto xsdt_entry::address() const noexcept -> table_header * + { + using type = decltype(xsdt_entry_data::address); + + constexpr auto size = sizeof(type); + constexpr auto offset = offsetof(xsdt_entry_data, address); + + auto const data = std::span{m_data.data() + offset, size}; + auto value = type{}; + + kstd::libc::memcpy(&value, data.data(), size); + + return reinterpret_cast(static_cast(value)); + } + + [[nodiscard]] auto xsdt_entry::length() const noexcept -> std::size_t + { + return sizeof(m_data); + } + +} // namespace acpi \ No newline at end of file diff --git a/libs/acpi/acpi/data/xsdt.hpp b/libs/acpi/acpi/data/xsdt.hpp new file mode 100644 index 0000000..965f23c --- /dev/null +++ b/libs/acpi/acpi/data/xsdt.hpp @@ -0,0 +1,42 @@ +#ifndef ACPI_DATA_XSDT_HPP +#define ACPI_DATA_XSDT_HPP + +#include +#include +#include +#include + +#include +#include + +namespace acpi +{ + + template<> + struct table_signature + { + constexpr char static const value[] = "XSDT"; // NOLINT + }; + + template<> + struct table_type> + { + using type = struct xsdt; + }; + + struct xsdt_entry + { + [[nodiscard]] auto address() const noexcept -> table_header *; + [[nodiscard]] auto length() const noexcept -> std::size_t; + + private: + std::array m_data{}; + }; + + struct xsdt : vla_table + { + }; + +} // namespace acpi + +#endif \ No newline at end of file diff --git a/libs/acpi/acpi/data/xsdt.test.cpp b/libs/acpi/acpi/data/xsdt.test.cpp new file mode 100644 index 0000000..7fb564c --- /dev/null +++ b/libs/acpi/acpi/data/xsdt.test.cpp @@ -0,0 +1,46 @@ +#include + +#include +#include +#include +#include + +#include + +SCENARIO("XSDT parsing", "[xsdt]") +{ + GIVEN("The basic compiled XSDT containing 8 table pointers") + { + auto data = acpi::test_data::tables::basic_xsdt(); + + WHEN("parsing the table") + { + auto xsdt = reinterpret_cast(data.data()); + + THEN("the signature is correct") + { + REQUIRE(xsdt->signature() == "XSDT"); + } + + THEN("validate returns true") + { + REQUIRE(xsdt->validate()); + } + + THEN("there are 8 entries in the table") + { + REQUIRE(std::distance(xsdt->begin(), xsdt->end()) == 8); + } + + THEN("the first entry has address 0x10") + { + REQUIRE(xsdt->cbegin()->address() == reinterpret_cast(0x10)); + } + + THEN("the length is sizeof(xsdt) + 8 * sizeof(xsdt_entry)") + { + REQUIRE(xsdt->length().value == sizeof(acpi::xsdt) + 8 * sizeof(acpi::xsdt_entry)); + } + } + } +} diff --git a/libs/acpi/test_data/basic_xsdt.asl b/libs/acpi/test_data/basic_xsdt.asl new file mode 100644 index 0000000..d8589f9 --- /dev/null +++ b/libs/acpi/test_data/basic_xsdt.asl @@ -0,0 +1,26 @@ +/* + * Intel ACPI Component Architecture + * iASL Compiler/Disassembler version 20251212 (64-bit version) + * Copyright (c) 2000 - 2025 Intel Corporation + * + * Template for [XSDT] ACPI Table (static data table) + * Format: [ByteLength] FieldName : HexFieldValue + */ +[0004] Signature : "XSDT" [Extended System Description Table] +[0004] Table Length : 00000064 +[0001] Revision : 01 +[0001] Checksum : 8B +[0006] Oem ID : "INTEL " +[0008] Oem Table ID : "TEMPLATE" +[0004] Oem Revision : 00000001 +[0004] Asl Compiler ID : "INTL" +[0004] Asl Compiler Revision : 20100528 + +[0008] ACPI Table Address 0 : 0000000000000010 +[0008] ACPI Table Address 1 : 0000000000000020 +[0008] ACPI Table Address 2 : 0000000000000030 +[0008] ACPI Table Address 3 : 0000000000000040 +[0008] ACPI Table Address 4 : 0000000000000050 +[0008] ACPI Table Address 5 : 0000000000000060 +[0008] ACPI Table Address 6 : 0000000000000070 +[0008] ACPI Table Address 7 : 0000000000000080 diff --git a/libs/acpi/test_data/tables.S b/libs/acpi/test_data/tables.S index da9a12f..641db6a 100644 --- a/libs/acpi/test_data/tables.S +++ b/libs/acpi/test_data/tables.S @@ -11,6 +11,7 @@ TABLE(basic_madt, "basic_madt.aml") TABLE(basic_rsdt, "basic_rsdt.aml") TABLE(basic_rsdp, "basic_rsdp.aml") +TABLE(basic_xsdt, "basic_xsdt.aml") TABLE(table_header, "table_header.aml") #undef TABLE diff --git a/libs/acpi/test_data/tables.hpp b/libs/acpi/test_data/tables.hpp index dc39b37..e91f1a5 100644 --- a/libs/acpi/test_data/tables.hpp +++ b/libs/acpi/test_data/tables.hpp @@ -18,6 +18,7 @@ namespace acpi::test_data::tables TABLE(basic_madt); TABLE(basic_rsdt); TABLE(basic_rsdp); + TABLE(basic_xsdt); TABLE(table_header); } // namespace acpi::test_data::tables -- cgit v1.2.3 From 9b4cbc6ba3f8059278a20a4893780717851ce8e4 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Tue, 21 Apr 2026 13:06:35 +0200 Subject: build: clean up configuration --- libs/acpi/CMakeLists.txt | 64 ++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 51 insertions(+), 13 deletions(-) (limited to 'libs/acpi') diff --git a/libs/acpi/CMakeLists.txt b/libs/acpi/CMakeLists.txt index 55d5b54..b0fc48f 100644 --- a/libs/acpi/CMakeLists.txt +++ b/libs/acpi/CMakeLists.txt @@ -6,17 +6,35 @@ project("acpi" LANGUAGES ASM CXX ) -add_library("acpi" STATIC) -add_library("libs::acpi" ALIAS "acpi") +include("CTest") -target_include_directories("acpi" PUBLIC - "${CMAKE_CURRENT_SOURCE_DIR}" -) +#[============================================================================[ +# External Dependencies +#]============================================================================] -file(GLOB_RECURSE ACPI_HEADERS - RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} - "acpi/*.hpp" -) +include("FetchContent") + +if (BUILD_TESTING) + FetchContent_Declare( + "Catch2" + URL "https://github.com/catchorg/Catch2/archive/refs/tags/v3.7.1.tar.gz" + URL_HASH "SHA256=c991b247a1a0d7bb9c39aa35faf0fe9e19764213f28ffba3109388e62ee0269c" + EXCLUDE_FROM_ALL + FIND_PACKAGE_ARGS + ) + + FetchContent_MakeAvailable("Catch2") + + find_package("Catch2") + include("Catch") +endif() + +#[============================================================================[ +# Library +#]============================================================================] + +add_library("acpi" STATIC) +add_library("acpi::lib" ALIAS "acpi") target_sources("acpi" PRIVATE "acpi/common/checksum.cpp" @@ -27,6 +45,11 @@ target_sources("acpi" PRIVATE "acpi/pointers.cpp" ) +file(GLOB_RECURSE ACPI_HEADERS + RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} + "acpi/*.hpp" +) + target_sources("acpi" PUBLIC FILE_SET HEADERS BASE_DIRS "acpi" @@ -34,11 +57,23 @@ target_sources("acpi" PUBLIC ${ACPI_HEADERS} ) +target_include_directories("acpi" PUBLIC + "${CMAKE_CURRENT_SOURCE_DIR}" +) + target_link_libraries("acpi" PUBLIC - "libs::kstd" + "kstd::lib" ) -if(NOT CMAKE_CROSSCOMPILING) +set_target_properties("acpi" PROPERTIES + VERIFY_INTERFACE_HEADER_SETS YES +) + +#[============================================================================[ +# Tests +#]============================================================================] + +if(BUILD_TESTING) find_program(IASL_EXE NAMES "iasl" REQUIRED) set(TEST_TABLES @@ -61,7 +96,10 @@ if(NOT CMAKE_CROSSCOMPILING) set_source_files_properties("test_data/tables.S" PROPERTIES OBJECT_DEPENDS "${GENERATED_TABLE_BLOBS}") - add_executable("acpi_tests" + add_executable("acpi_tests") + add_executable("acpi::tests" ALIAS "acpi_tests") + + target_sources("acpi_tests" PRIVATE "acpi/common/table_header.test.cpp" "acpi/data/madt.test.cpp" "acpi/data/rsdt.test.cpp" @@ -77,7 +115,7 @@ if(NOT CMAKE_CROSSCOMPILING) target_link_libraries("acpi_tests" PRIVATE "Catch2::Catch2WithMain" - "libs::acpi" + "acpi::lib" ) set_target_properties("acpi_tests" PROPERTIES -- cgit v1.2.3 From e3fa6b1adbd7fce3b080d75fd0959949b7d3bef4 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Tue, 21 Apr 2026 14:13:55 +0200 Subject: acpi: enable test coverage --- libs/acpi/CMakeLists.txt | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'libs/acpi') diff --git a/libs/acpi/CMakeLists.txt b/libs/acpi/CMakeLists.txt index b0fc48f..b4d11d9 100644 --- a/libs/acpi/CMakeLists.txt +++ b/libs/acpi/CMakeLists.txt @@ -46,6 +46,7 @@ target_sources("acpi" PRIVATE ) file(GLOB_RECURSE ACPI_HEADERS + CONFIGURE_DEPENDS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "acpi/*.hpp" ) @@ -96,6 +97,10 @@ if(BUILD_TESTING) set_source_files_properties("test_data/tables.S" PROPERTIES OBJECT_DEPENDS "${GENERATED_TABLE_BLOBS}") + if(COMMAND "enable_coverage") + enable_coverage("acpi") + endif() + add_executable("acpi_tests") add_executable("acpi::tests" ALIAS "acpi_tests") -- cgit v1.2.3 From e8ce02d63f096147fc54824f0a45c23e3a3ced25 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Tue, 21 Apr 2026 14:44:01 +0200 Subject: libs: prepare for clang-tidy --- libs/acpi/CMakeLists.txt | 2 -- 1 file changed, 2 deletions(-) (limited to 'libs/acpi') diff --git a/libs/acpi/CMakeLists.txt b/libs/acpi/CMakeLists.txt index b4d11d9..e73c6b3 100644 --- a/libs/acpi/CMakeLists.txt +++ b/libs/acpi/CMakeLists.txt @@ -124,8 +124,6 @@ if(BUILD_TESTING) ) set_target_properties("acpi_tests" PROPERTIES - C_CLANG_TIDY "" - CXX_CLANG_TIDY "" EXCLUDE_FROM_ALL NO ) -- cgit v1.2.3 From 2d8fed40bd0d0f8144783b6b344dc79944291b72 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Thu, 23 Apr 2026 13:31:17 +0200 Subject: chore: organize includes --- libs/acpi/acpi/common/table_header.cpp | 4 ++-- libs/acpi/acpi/common/table_header.test.cpp | 4 +++- libs/acpi/acpi/data/madt.cpp | 4 ++-- libs/acpi/acpi/data/madt.hpp | 8 ++++---- libs/acpi/acpi/data/madt.test.cpp | 6 ++++-- libs/acpi/acpi/data/rsdt.cpp | 5 +++-- libs/acpi/acpi/data/rsdt.test.cpp | 9 ++++++--- libs/acpi/acpi/data/xsdt.cpp | 5 +++-- libs/acpi/acpi/data/xsdt.test.cpp | 9 ++++++--- libs/acpi/acpi/pointers.cpp | 5 +++-- libs/acpi/acpi/pointers.test.cpp | 1 + 11 files changed, 37 insertions(+), 23 deletions(-) (limited to 'libs/acpi') diff --git a/libs/acpi/acpi/common/table_header.cpp b/libs/acpi/acpi/common/table_header.cpp index c69ff5d..6a7a4dc 100644 --- a/libs/acpi/acpi/common/table_header.cpp +++ b/libs/acpi/acpi/common/table_header.cpp @@ -1,8 +1,8 @@ +#include + #include #include -#include - #include #include #include diff --git a/libs/acpi/acpi/common/table_header.test.cpp b/libs/acpi/acpi/common/table_header.test.cpp index d6976b3..53cdb26 100644 --- a/libs/acpi/acpi/common/table_header.test.cpp +++ b/libs/acpi/acpi/common/table_header.test.cpp @@ -1,7 +1,9 @@ +#include + #include -#include #include + #include SCENARIO("Common table header parsing", "[common_table_header]") diff --git a/libs/acpi/acpi/data/madt.cpp b/libs/acpi/acpi/data/madt.cpp index a8d4741..1a8b6d3 100644 --- a/libs/acpi/acpi/data/madt.cpp +++ b/libs/acpi/acpi/data/madt.cpp @@ -1,7 +1,7 @@ -#include - #include +#include + #include #include #include diff --git a/libs/acpi/acpi/data/madt.hpp b/libs/acpi/acpi/data/madt.hpp index 8307826..b76daa4 100644 --- a/libs/acpi/acpi/data/madt.hpp +++ b/libs/acpi/acpi/data/madt.hpp @@ -3,14 +3,14 @@ // IWYU pragma: private, include -#include -#include -#include - #include #include #include +#include +#include +#include + #include #include #include diff --git a/libs/acpi/acpi/data/madt.test.cpp b/libs/acpi/acpi/data/madt.test.cpp index 6795499..5d3b366 100644 --- a/libs/acpi/acpi/data/madt.test.cpp +++ b/libs/acpi/acpi/data/madt.test.cpp @@ -1,11 +1,13 @@ +#include + #include -#include #include -#include #include +#include + SCENARIO("MADT parsing", "[madt]") { GIVEN("The basic compiled MADT containing a single LAPIC entry and the default x86 LAPIC address") diff --git a/libs/acpi/acpi/data/rsdt.cpp b/libs/acpi/acpi/data/rsdt.cpp index fe108c7..80e209d 100644 --- a/libs/acpi/acpi/data/rsdt.cpp +++ b/libs/acpi/acpi/data/rsdt.cpp @@ -1,7 +1,8 @@ -#include +#include #include -#include + +#include #include #include diff --git a/libs/acpi/acpi/data/rsdt.test.cpp b/libs/acpi/acpi/data/rsdt.test.cpp index 937dce0..a6dd416 100644 --- a/libs/acpi/acpi/data/rsdt.test.cpp +++ b/libs/acpi/acpi/data/rsdt.test.cpp @@ -1,12 +1,15 @@ -#include +#include #include -#include + +#include + #include -#include #include +#include + SCENARIO("RSDT parsing", "[rsdt]") { GIVEN("The basic compiled RSDT containing 8 table pointers") diff --git a/libs/acpi/acpi/data/xsdt.cpp b/libs/acpi/acpi/data/xsdt.cpp index b4202b8..b77aeab 100644 --- a/libs/acpi/acpi/data/xsdt.cpp +++ b/libs/acpi/acpi/data/xsdt.cpp @@ -1,7 +1,8 @@ -#include +#include #include -#include + +#include #include #include diff --git a/libs/acpi/acpi/data/xsdt.test.cpp b/libs/acpi/acpi/data/xsdt.test.cpp index 7fb564c..cc18a66 100644 --- a/libs/acpi/acpi/data/xsdt.test.cpp +++ b/libs/acpi/acpi/data/xsdt.test.cpp @@ -1,12 +1,15 @@ -#include +#include #include -#include + +#include + #include -#include #include +#include + SCENARIO("XSDT parsing", "[xsdt]") { GIVEN("The basic compiled XSDT containing 8 table pointers") diff --git a/libs/acpi/acpi/pointers.cpp b/libs/acpi/acpi/pointers.cpp index 45a42ce..2ac8d31 100644 --- a/libs/acpi/acpi/pointers.cpp +++ b/libs/acpi/acpi/pointers.cpp @@ -1,7 +1,8 @@ -#include +#include #include -#include + +#include #include #include diff --git a/libs/acpi/acpi/pointers.test.cpp b/libs/acpi/acpi/pointers.test.cpp index 06ce1a4..d7b700d 100644 --- a/libs/acpi/acpi/pointers.test.cpp +++ b/libs/acpi/acpi/pointers.test.cpp @@ -1,4 +1,5 @@ #include + #include #include -- cgit v1.2.3 From d906d70c94c2a40d5fc6fd26056c7bc57d540002 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Thu, 23 Apr 2026 17:16:34 +0200 Subject: acpi: move test data header --- libs/acpi/CMakeLists.txt | 4 ++-- libs/acpi/acpi/common/table_header.test.cpp | 4 ++-- libs/acpi/acpi/data/madt.test.cpp | 4 ++-- libs/acpi/acpi/data/rsdt.test.cpp | 3 +-- libs/acpi/acpi/data/xsdt.test.cpp | 3 +-- libs/acpi/acpi/test_data/tables.S | 17 +++++++++++++++++ libs/acpi/acpi/test_data/tables.hpp | 28 ++++++++++++++++++++++++++++ libs/acpi/test_data/tables.S | 17 ----------------- libs/acpi/test_data/tables.hpp | 28 ---------------------------- 9 files changed, 53 insertions(+), 55 deletions(-) create mode 100644 libs/acpi/acpi/test_data/tables.S create mode 100644 libs/acpi/acpi/test_data/tables.hpp delete mode 100644 libs/acpi/test_data/tables.S delete mode 100644 libs/acpi/test_data/tables.hpp (limited to 'libs/acpi') diff --git a/libs/acpi/CMakeLists.txt b/libs/acpi/CMakeLists.txt index e73c6b3..d6d607a 100644 --- a/libs/acpi/CMakeLists.txt +++ b/libs/acpi/CMakeLists.txt @@ -95,7 +95,7 @@ if(BUILD_TESTING) list(APPEND GENERATED_TABLE_BLOBS "${CMAKE_CURRENT_BINARY_DIR}/test_data/${TABLE}.aml") endforeach() - set_source_files_properties("test_data/tables.S" PROPERTIES OBJECT_DEPENDS "${GENERATED_TABLE_BLOBS}") + set_source_files_properties("acpi/test_data/tables.S" PROPERTIES OBJECT_DEPENDS "${GENERATED_TABLE_BLOBS}") if(COMMAND "enable_coverage") enable_coverage("acpi") @@ -111,7 +111,7 @@ if(BUILD_TESTING) "acpi/data/xsdt.test.cpp" "acpi/pointers.test.cpp" - "test_data/tables.S" + "acpi/test_data/tables.S" ) target_include_directories("acpi_tests" PRIVATE diff --git a/libs/acpi/acpi/common/table_header.test.cpp b/libs/acpi/acpi/common/table_header.test.cpp index 53cdb26..ddc879e 100644 --- a/libs/acpi/acpi/common/table_header.test.cpp +++ b/libs/acpi/acpi/common/table_header.test.cpp @@ -1,11 +1,11 @@ #include +#include + #include #include -#include - SCENARIO("Common table header parsing", "[common_table_header]") { GIVEN("A valid compiled table header") diff --git a/libs/acpi/acpi/data/madt.test.cpp b/libs/acpi/acpi/data/madt.test.cpp index 5d3b366..1b95a74 100644 --- a/libs/acpi/acpi/data/madt.test.cpp +++ b/libs/acpi/acpi/data/madt.test.cpp @@ -1,13 +1,13 @@ #include +#include + #include #include #include -#include - SCENARIO("MADT parsing", "[madt]") { GIVEN("The basic compiled MADT containing a single LAPIC entry and the default x86 LAPIC address") diff --git a/libs/acpi/acpi/data/rsdt.test.cpp b/libs/acpi/acpi/data/rsdt.test.cpp index a6dd416..47992ce 100644 --- a/libs/acpi/acpi/data/rsdt.test.cpp +++ b/libs/acpi/acpi/data/rsdt.test.cpp @@ -1,6 +1,7 @@ #include #include +#include #include @@ -8,8 +9,6 @@ #include -#include - SCENARIO("RSDT parsing", "[rsdt]") { GIVEN("The basic compiled RSDT containing 8 table pointers") diff --git a/libs/acpi/acpi/data/xsdt.test.cpp b/libs/acpi/acpi/data/xsdt.test.cpp index cc18a66..77a5340 100644 --- a/libs/acpi/acpi/data/xsdt.test.cpp +++ b/libs/acpi/acpi/data/xsdt.test.cpp @@ -1,6 +1,7 @@ #include #include +#include #include @@ -8,8 +9,6 @@ #include -#include - SCENARIO("XSDT parsing", "[xsdt]") { GIVEN("The basic compiled XSDT containing 8 table pointers") diff --git a/libs/acpi/acpi/test_data/tables.S b/libs/acpi/acpi/test_data/tables.S new file mode 100644 index 0000000..641db6a --- /dev/null +++ b/libs/acpi/acpi/test_data/tables.S @@ -0,0 +1,17 @@ +.section .rodata + +.balign 16 + +#define TABLE(name, file) \ + .global name##_start; \ + .global name##_end; \ + name##_start: .incbin file; \ + name##_end: + +TABLE(basic_madt, "basic_madt.aml") +TABLE(basic_rsdt, "basic_rsdt.aml") +TABLE(basic_rsdp, "basic_rsdp.aml") +TABLE(basic_xsdt, "basic_xsdt.aml") +TABLE(table_header, "table_header.aml") + +#undef TABLE diff --git a/libs/acpi/acpi/test_data/tables.hpp b/libs/acpi/acpi/test_data/tables.hpp new file mode 100644 index 0000000..e91f1a5 --- /dev/null +++ b/libs/acpi/acpi/test_data/tables.hpp @@ -0,0 +1,28 @@ +#ifndef ACPI_TEST_DATA_TABLES_HPP +#define ACPI_TEST_DATA_TABLES_HPP + +#include +#include + +#define TABLE(name) \ + extern "C" std::byte const name##_start; \ + extern "C" std::byte const name##_end; \ + auto inline name()->std::span \ + { \ + return {&name##_start, &name##_end}; \ + } + +namespace acpi::test_data::tables +{ + + TABLE(basic_madt); + TABLE(basic_rsdt); + TABLE(basic_rsdp); + TABLE(basic_xsdt); + TABLE(table_header); + +} // namespace acpi::test_data::tables + +#undef TABLE + +#endif diff --git a/libs/acpi/test_data/tables.S b/libs/acpi/test_data/tables.S deleted file mode 100644 index 641db6a..0000000 --- a/libs/acpi/test_data/tables.S +++ /dev/null @@ -1,17 +0,0 @@ -.section .rodata - -.balign 16 - -#define TABLE(name, file) \ - .global name##_start; \ - .global name##_end; \ - name##_start: .incbin file; \ - name##_end: - -TABLE(basic_madt, "basic_madt.aml") -TABLE(basic_rsdt, "basic_rsdt.aml") -TABLE(basic_rsdp, "basic_rsdp.aml") -TABLE(basic_xsdt, "basic_xsdt.aml") -TABLE(table_header, "table_header.aml") - -#undef TABLE diff --git a/libs/acpi/test_data/tables.hpp b/libs/acpi/test_data/tables.hpp deleted file mode 100644 index e91f1a5..0000000 --- a/libs/acpi/test_data/tables.hpp +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef ACPI_TEST_DATA_TABLES_HPP -#define ACPI_TEST_DATA_TABLES_HPP - -#include -#include - -#define TABLE(name) \ - extern "C" std::byte const name##_start; \ - extern "C" std::byte const name##_end; \ - auto inline name()->std::span \ - { \ - return {&name##_start, &name##_end}; \ - } - -namespace acpi::test_data::tables -{ - - TABLE(basic_madt); - TABLE(basic_rsdt); - TABLE(basic_rsdp); - TABLE(basic_xsdt); - TABLE(table_header); - -} // namespace acpi::test_data::tables - -#undef TABLE - -#endif -- cgit v1.2.3 From 9ff0dffb026eae3b80e3e0b8bbb941e3e3b8b01f Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Fri, 1 May 2026 10:16:49 +0200 Subject: acpi: silence IASL compiler output --- libs/acpi/CMakeLists.txt | 7 ++++++- libs/acpi/cmake/Scripts/IaslCompile.cmake | 16 ++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) create mode 100644 libs/acpi/cmake/Scripts/IaslCompile.cmake (limited to 'libs/acpi') diff --git a/libs/acpi/CMakeLists.txt b/libs/acpi/CMakeLists.txt index d6d607a..2c4d76d 100644 --- a/libs/acpi/CMakeLists.txt +++ b/libs/acpi/CMakeLists.txt @@ -87,7 +87,12 @@ if(BUILD_TESTING) foreach(TABLE IN LISTS TEST_TABLES) add_custom_command(OUTPUT "test_data/${TABLE}.aml" - COMMAND "${IASL_EXE}" -p "test_data/${TABLE}.aml" "${CMAKE_CURRENT_SOURCE_DIR}/test_data/${TABLE}.asl" + COMMAND ${CMAKE_COMMAND} + "-DIASL_EXE=${IASL_EXE}" + "-DIASL_OUTPUT=test_data/${TABLE}.aml" + "-DIASL_INPUT=${CMAKE_CURRENT_SOURCE_DIR}/test_data/${TABLE}.asl" + "-P" + "${CMAKE_CURRENT_SOURCE_DIR}/cmake/Scripts/IaslCompile.cmake" DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/test_data/${TABLE}.asl" COMMENT "Compiling test_data/${TABLE}.asl" VERBATIM diff --git a/libs/acpi/cmake/Scripts/IaslCompile.cmake b/libs/acpi/cmake/Scripts/IaslCompile.cmake new file mode 100644 index 0000000..ff73b34 --- /dev/null +++ b/libs/acpi/cmake/Scripts/IaslCompile.cmake @@ -0,0 +1,16 @@ +execute_process( + COMMAND + "${IASL_EXE}" + "-vs" + "-p" + "${IASL_OUTPUT}" + "${IASL_INPUT}" + OUTPUT_VARIABLE IASL_OUT + ERROR_VARIABLE IASL_ERR + RESULT_VARIABLE IASL_RES +) + +if(NOT IASL_RES EQUAL 0) + message(STATUS "${IASL_OUT}") + message(FATAL_ERROR "${IASL_ERR}") +endif() -- cgit v1.2.3 From a50d6cfcea67b11f6689ec825afc2e2b33252714 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Mon, 18 May 2026 15:21:39 +0200 Subject: ci: enable jUnit style test reports --- libs/acpi/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'libs/acpi') diff --git a/libs/acpi/CMakeLists.txt b/libs/acpi/CMakeLists.txt index 2c4d76d..135ce6a 100644 --- a/libs/acpi/CMakeLists.txt +++ b/libs/acpi/CMakeLists.txt @@ -132,5 +132,5 @@ if(BUILD_TESTING) EXCLUDE_FROM_ALL NO ) - catch_discover_tests("acpi_tests") + catch_discover_tests("acpi_tests" ${CATCH_TEST_ARGS}) endif() -- cgit v1.2.3 From 033ecf6714089d2ce331152f5e120567f8d546cf Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Tue, 19 May 2026 12:48:08 +0200 Subject: build: clean up dependencies --- libs/acpi/CMakeLists.txt | 26 ++++---------------------- 1 file changed, 4 insertions(+), 22 deletions(-) (limited to 'libs/acpi') diff --git a/libs/acpi/CMakeLists.txt b/libs/acpi/CMakeLists.txt index 135ce6a..1d03bb5 100644 --- a/libs/acpi/CMakeLists.txt +++ b/libs/acpi/CMakeLists.txt @@ -8,27 +8,6 @@ project("acpi" include("CTest") -#[============================================================================[ -# External Dependencies -#]============================================================================] - -include("FetchContent") - -if (BUILD_TESTING) - FetchContent_Declare( - "Catch2" - URL "https://github.com/catchorg/Catch2/archive/refs/tags/v3.7.1.tar.gz" - URL_HASH "SHA256=c991b247a1a0d7bb9c39aa35faf0fe9e19764213f28ffba3109388e62ee0269c" - EXCLUDE_FROM_ALL - FIND_PACKAGE_ARGS - ) - - FetchContent_MakeAvailable("Catch2") - - find_package("Catch2") - include("Catch") -endif() - #[============================================================================[ # Library #]============================================================================] @@ -75,6 +54,9 @@ set_target_properties("acpi" PROPERTIES #]============================================================================] if(BUILD_TESTING) + find_package("Catch2") + include("Catch") + find_program(IASL_EXE NAMES "iasl" REQUIRED) set(TEST_TABLES @@ -132,5 +114,5 @@ if(BUILD_TESTING) EXCLUDE_FROM_ALL NO ) - catch_discover_tests("acpi_tests" ${CATCH_TEST_ARGS}) + catch_discover_tests("acpi::tests" ${CATCH_TEST_ARGS}) endif() -- cgit v1.2.3 From 46d3f8978e9f4235064daf5f19de5bf3054e7c24 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Tue, 2 Jun 2026 16:38:30 +0200 Subject: acpi: fix two lint issues --- libs/acpi/acpi/common/basic_table.hpp | 5 +++++ libs/acpi/acpi/common/vla_table.hpp | 5 +++++ 2 files changed, 10 insertions(+) (limited to 'libs/acpi') diff --git a/libs/acpi/acpi/common/basic_table.hpp b/libs/acpi/acpi/common/basic_table.hpp index 33f23d5..f5b5b27 100644 --- a/libs/acpi/acpi/common/basic_table.hpp +++ b/libs/acpi/acpi/common/basic_table.hpp @@ -28,6 +28,11 @@ namespace acpi { return signature() == table_signature_v && validate_checksum(); } + + private: + friend TableType; + + constexpr basic_table() noexcept = default; }; } // namespace acpi diff --git a/libs/acpi/acpi/common/vla_table.hpp b/libs/acpi/acpi/common/vla_table.hpp index a65a28e..d3f33a7 100644 --- a/libs/acpi/acpi/common/vla_table.hpp +++ b/libs/acpi/acpi/common/vla_table.hpp @@ -109,6 +109,11 @@ namespace acpi { return end(); } + + private: + friend TableType; + + constexpr vla_table() noexcept = default; }; } // namespace acpi -- cgit v1.2.3