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') 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