diff options
Diffstat (limited to 'libs/acpi')
28 files changed, 864 insertions, 307 deletions
diff --git a/libs/acpi/CMakeLists.txt b/libs/acpi/CMakeLists.txt index 30e1aca..55d5b54 100644 --- a/libs/acpi/CMakeLists.txt +++ b/libs/acpi/CMakeLists.txt @@ -19,10 +19,12 @@ file(GLOB_RECURSE ACPI_HEADERS ) target_sources("acpi" PRIVATE - "acpi/checksum.cpp" - "acpi/madt.cpp" + "acpi/common/checksum.cpp" + "acpi/common/table_header.cpp" + "acpi/data/madt.cpp" + "acpi/data/rsdt.cpp" + "acpi/data/xsdt.cpp" "acpi/pointers.cpp" - "acpi/sdt.cpp" ) target_sources("acpi" PUBLIC @@ -43,6 +45,8 @@ if(NOT CMAKE_CROSSCOMPILING) "basic_madt" "basic_rsdt" "basic_rsdp" + "basic_xsdt" + "table_header" ) foreach(TABLE IN LISTS TEST_TABLES) @@ -58,7 +62,10 @@ if(NOT CMAKE_CROSSCOMPILING) set_source_files_properties("test_data/tables.S" PROPERTIES OBJECT_DEPENDS "${GENERATED_TABLE_BLOBS}") add_executable("acpi_tests" - "acpi/madt.test.cpp" + "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 fb358cc..0da44a8 100644 --- a/libs/acpi/acpi/acpi.hpp +++ b/libs/acpi/acpi/acpi.hpp @@ -1,10 +1,12 @@ #ifndef ACPI_ACPI_HPP #define ACPI_ACPI_HPP -#include <acpi/checksum.hpp> // IWYU pragma: export -#include <acpi/madt.hpp> // IWYU pragma: export -#include <acpi/pointers.hpp> // IWYU pragma: export -#include <acpi/sdt.hpp> // IWYU pragma: export -#include <acpi/table_type.hpp> // IWYU pragma: export +#include <acpi/common/checksum.hpp> // IWYU pragma: export +#include <acpi/common/table_signature.hpp> // IWYU pragma: export +#include <acpi/common/table_type.hpp> // IWYU pragma: export +#include <acpi/data/madt.hpp> // IWYU pragma: export +#include <acpi/data/rsdt.hpp> // IWYU pragma: export +#include <acpi/data/xsdt.hpp> // IWYU pragma: export +#include <acpi/pointers.hpp> // IWYU pragma: export #endif diff --git a/libs/acpi/acpi/common/basic_table.hpp b/libs/acpi/acpi/common/basic_table.hpp new file mode 100644 index 0000000..33f23d5 --- /dev/null +++ b/libs/acpi/acpi/common/basic_table.hpp @@ -0,0 +1,35 @@ +#ifndef ACPI_COMMON_BASIC_TABLE_HPP +#define ACPI_COMMON_BASIC_TABLE_HPP + +#include <acpi/common/checksum.hpp> +#include <acpi/common/table_header.hpp> +#include <acpi/common/table_signature.hpp> + +#include <cstddef> +#include <span> + +namespace acpi +{ + + template<typename TableType> + struct basic_table : table_header + { + [[nodiscard]] auto validate_checksum() const noexcept -> bool + { + return acpi::validate_checksum(as_span()); + } + + [[nodiscard]] auto as_span() const noexcept -> std::span<std::byte const> + { + return {reinterpret_cast<std::byte const *>(this), length().value}; + } + + [[nodiscard]] auto validate() const noexcept -> bool + { + return signature() == table_signature_v<TableType> && validate_checksum(); + } + }; + +} // namespace acpi + +#endif
\ No newline at end of file diff --git a/libs/acpi/acpi/checksum.cpp b/libs/acpi/acpi/common/checksum.cpp index 56275c8..09425dd 100644 --- a/libs/acpi/acpi/checksum.cpp +++ b/libs/acpi/acpi/common/checksum.cpp @@ -1,4 +1,4 @@ -#include <acpi/checksum.hpp> +#include <acpi/common/checksum.hpp> #include <algorithm> #include <cstddef> diff --git a/libs/acpi/acpi/checksum.hpp b/libs/acpi/acpi/common/checksum.hpp index a92c242..a92c242 100644 --- a/libs/acpi/acpi/checksum.hpp +++ b/libs/acpi/acpi/common/checksum.hpp diff --git a/libs/acpi/acpi/common/table_header.cpp b/libs/acpi/acpi/common/table_header.cpp new file mode 100644 index 0000000..c69ff5d --- /dev/null +++ b/libs/acpi/acpi/common/table_header.cpp @@ -0,0 +1,130 @@ +#include <kstd/cstring> +#include <kstd/units> + +#include <acpi/common/table_header.hpp> + +#include <array> +#include <cstddef> +#include <cstdint> +#include <span> +#include <string_view> + +namespace acpi +{ + + struct common_table_header_data + { + std::array<char, 4> signature; + std::uint32_t length; + std::uint8_t revision; + std::uint8_t checksum; + std::array<char, 6> oem_id; + std::array<char, 8> oem_table_id; + std::uint32_t oem_revision; + std::array<char, 4> creator_id; + std::uint32_t creator_revision; + }; + + static_assert(sizeof(common_table_header_data) == common_table_header_size); + + auto 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<std::byte const, size>{m_data.data() + offset, size}; + auto value = type{}; + + kstd::libc::memcpy(&value, data.data(), size); + + return value; + } + + 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); + + auto const base = reinterpret_cast<char const *>(m_data.data()); + + return std::string_view{base + offset, size}; + } + + auto 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<std::byte const, size>{m_data.data() + offset, size}; + auto raw_value = type{}; + + kstd::libc::memcpy(&raw_value, data.data(), size); + + return kstd::units::bytes{raw_value}; + } + + 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); + + auto const base = reinterpret_cast<char const *>(m_data.data()); + + return std::string_view{base + offset, size}; + } + + 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); + + auto const base = reinterpret_cast<char const *>(m_data.data()); + + return std::string_view{base + offset, size}; + } + + auto 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<std::byte const, size>{m_data.data() + offset, size}; + auto value = type{}; + + kstd::libc::memcpy(&value, data.data(), size); + + return value; + } + + auto 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<std::byte const, size>{m_data.data() + offset, size}; + auto value = type{}; + + kstd::libc::memcpy(&value, data.data(), size); + + return value; + } + + 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); + + auto const base = reinterpret_cast<char const *>(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..471fed8 --- /dev/null +++ b/libs/acpi/acpi/common/table_header.hpp @@ -0,0 +1,56 @@ +#ifndef ACPI_COMMON_TABLE_HEADER_HPP +#define ACPI_COMMON_TABLE_HEADER_HPP + +// IWYU pragma: private, include <acpi/acpi.hpp> + +#include <kstd/units> + +#include <array> +#include <cstddef> +#include <cstdint> +#include <string_view> + +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 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; + + private: + std::array<std::byte, common_table_header_size> 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..d6976b3 --- /dev/null +++ b/libs/acpi/acpi/common/table_header.test.cpp @@ -0,0 +1,58 @@ +#include <kstd/units> + +#include <acpi/common/table_header.hpp> +#include <catch2/catch_test_macros.hpp> +#include <test_data/tables.hpp> + +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<acpi::table_header const *>(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<acpi::table_header>); + } + + 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/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 <acpi/acpi.hpp> + +namespace acpi +{ + + template<typename TableType> + struct table_signature; + + template<typename TableType> + constexpr auto table_signature_v = table_signature<TableType>::value; + +} // namespace acpi + +#endif diff --git a/libs/acpi/acpi/table_type.hpp b/libs/acpi/acpi/common/table_type.hpp index 7fdd7e3..bc427c7 100644 --- a/libs/acpi/acpi/table_type.hpp +++ b/libs/acpi/acpi/common/table_type.hpp @@ -1,5 +1,5 @@ -#ifndef ACPI_TABLE_TYPE_HPP -#define ACPI_TABLE_TYPE_HPP +#ifndef ACPI_COMMON_TABLE_TYPE_HPP +#define ACPI_COMMON_TABLE_TYPE_HPP // IWYU pragma: private, include <acpi/acpi.hpp> diff --git a/libs/acpi/acpi/common/vla_table.hpp b/libs/acpi/acpi/common/vla_table.hpp new file mode 100644 index 0000000..a65a28e --- /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 <acpi/common/basic_table.hpp> + +#include <cstddef> +#include <iterator> + +namespace acpi +{ + + template<typename EntryType> + 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<std::byte *>(m_entry); + decayed += m_entry->length(); + m_entry = std::bit_cast<pointer>(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<typename EntryType, typename TableType> + struct vla_table : basic_table<TableType> + { + using entry_type = EntryType; + using iterator = vla_table_iterator<EntryType>; + using const_iterator = vla_table_iterator<EntryType const>; + + [[nodiscard]] auto begin() noexcept -> iterator + { + auto base = std::bit_cast<std::byte *>(this); + base += sizeof(TableType); + auto limit = std::bit_cast<std::byte *>(this); + limit += this->length().value; + return iterator{std::bit_cast<entry_type *>(base), std::bit_cast<entry_type *>(limit)}; + } + + [[nodiscard]] auto end() noexcept -> iterator + { + return iterator{}; + } + + [[nodiscard]] auto begin() const noexcept -> const_iterator + { + auto base = std::bit_cast<std::byte *>(this); + base += sizeof(TableType); + auto limit = std::bit_cast<std::byte *>(this); + limit += this->length().value; + return const_iterator{std::bit_cast<entry_type const *>(base), std::bit_cast<entry_type const *>(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/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 <kstd/cstring> + +#include <acpi/data/madt.hpp> + +#include <bit> +#include <cstddef> +#include <cstdint> +#include <span> + +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<std::byte const, size>{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<std::byte const, size>{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<enum type>(*(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<std::size_t>(*(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<std::uint8_t>(*(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<std::byte const, size>{m_data.data() + offset, size}; + auto value = type{}; + + kstd::libc::memcpy(&value, data.data(), size); + + return static_cast<enum flags>(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<std::uint32_t>(*(m_data.data() + field_offset)); + } + +} // namespace acpi diff --git a/libs/acpi/acpi/madt.hpp b/libs/acpi/acpi/data/madt.hpp index 8b75f58..8307826 100644 --- a/libs/acpi/acpi/madt.hpp +++ b/libs/acpi/acpi/data/madt.hpp @@ -7,9 +7,11 @@ #include <kstd/os/error.hpp> #include <kstd/units> -#include <acpi/sdt.hpp> -#include <acpi/table_type.hpp> +#include <acpi/common/table_signature.hpp> +#include <acpi/common/table_type.hpp> +#include <acpi/common/vla_table.hpp> +#include <array> #include <cstddef> #include <cstdint> #include <ranges> @@ -18,7 +20,19 @@ namespace acpi { - struct [[gnu::packed]] madt_entry + template<> + struct table_signature<struct madt> + { + constexpr char static const value[] = "APIC"; // NOLINT + }; + + template<> + struct table_type<table_signature_v<struct madt>> + { + 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<std::byte, 2> m_data{}; }; //! The Multiple APIC Description Table (MADT) - struct [[gnu::packed]] madt : sdt + struct madt : vla_table<madt_entry, madt> { - using iterator = sdt_iterator<madt_entry const>; - 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<typename EntryType> [[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<std::byte, 8> 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<madt_table_signature> - { - using type = madt; + std::array<std::byte, 6> m_data{}; }; } // namespace acpi template<> -struct kstd::ext::is_bitfield_enum<acpi::processor_local_apic::flags> : std::true_type +struct kstd::ext::is_bitfield_enum<enum acpi::processor_local_apic_entry::flags> : std::true_type { }; diff --git a/libs/acpi/acpi/madt.test.cpp b/libs/acpi/acpi/data/madt.test.cpp index 8926192..6795499 100644 --- a/libs/acpi/acpi/madt.test.cpp +++ b/libs/acpi/acpi/data/madt.test.cpp @@ -1,6 +1,6 @@ #include <kstd/units> -#include <acpi/madt.hpp> +#include <acpi/data/madt.hpp> #include <catch2/catch_test_macros.hpp> #include <test_data/tables.hpp> @@ -38,7 +38,7 @@ SCENARIO("MADT parsing", "[madt]") THEN("the length is sizeof(madt) + sizeof(processor_local_apic)") { - REQUIRE(madt->length() == kstd::type_size<acpi::madt> + kstd::type_size<acpi::processor_local_apic>); + REQUIRE(madt->length().value == 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<acpi::processor_local_apic>()) == 1); + REQUIRE(std::ranges::distance(madt->only<acpi::processor_local_apic_entry>()) == 1); } } } diff --git a/libs/acpi/acpi/data/rsdt.cpp b/libs/acpi/acpi/data/rsdt.cpp new file mode 100644 index 0000000..fe108c7 --- /dev/null +++ b/libs/acpi/acpi/data/rsdt.cpp @@ -0,0 +1,38 @@ +#include <kstd/cstring> + +#include <acpi/common/table_header.hpp> +#include <acpi/data/rsdt.hpp> + +#include <cstddef> +#include <cstdint> +#include <span> + +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<std::byte const, size>{m_data.data() + offset, size}; + auto value = type{}; + + kstd::libc::memcpy(&value, data.data(), size); + + return reinterpret_cast<table_header *>(static_cast<uintptr_t>(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..a661187 --- /dev/null +++ b/libs/acpi/acpi/data/rsdt.hpp @@ -0,0 +1,42 @@ +#ifndef ACPI_DATA_RSDT_HPP +#define ACPI_DATA_RSDT_HPP + +#include <acpi/common/table_header.hpp> +#include <acpi/common/table_signature.hpp> +#include <acpi/common/table_type.hpp> +#include <acpi/common/vla_table.hpp> + +#include <array> +#include <cstddef> + +namespace acpi +{ + + template<> + struct table_signature<struct rsdt> + { + constexpr char static const value[] = "RSDT"; // NOLINT + }; + + template<> + struct table_type<table_signature_v<struct rsdt>> + { + 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<std::byte, 4> m_data{}; + }; + + struct rsdt : vla_table<rsdt_entry, rsdt> + { + }; + +} // 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..937dce0 --- /dev/null +++ b/libs/acpi/acpi/data/rsdt.test.cpp @@ -0,0 +1,46 @@ +#include <kstd/units> + +#include <acpi/acpi.hpp> +#include <acpi/data/rsdt.hpp> +#include <catch2/catch_test_macros.hpp> +#include <test_data/tables.hpp> + +#include <iterator> + +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<acpi::rsdt const *>(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<acpi::table_header *>(0x10)); + } + + THEN("the length is sizeof(rsdt) + 8 * sizeof(rsdt_entry)") + { + REQUIRE(rsdt->length().value == sizeof(acpi::rsdt) + 8 * sizeof(acpi::rsdt_entry)); + } + } + } +} 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 <kstd/cstring> + +#include <acpi/common/table_header.hpp> +#include <acpi/data/xsdt.hpp> + +#include <cstddef> +#include <cstdint> +#include <span> + +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<std::byte const, size>{m_data.data() + offset, size}; + auto value = type{}; + + kstd::libc::memcpy(&value, data.data(), size); + + return reinterpret_cast<table_header *>(static_cast<uintptr_t>(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 <acpi/common/table_header.hpp> +#include <acpi/common/table_signature.hpp> +#include <acpi/common/table_type.hpp> +#include <acpi/common/vla_table.hpp> + +#include <array> +#include <cstddef> + +namespace acpi +{ + + template<> + struct table_signature<struct xsdt> + { + constexpr char static const value[] = "XSDT"; // NOLINT + }; + + template<> + struct table_type<table_signature_v<struct xsdt>> + { + 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<std::byte, 8> m_data{}; + }; + + struct xsdt : vla_table<xsdt_entry, xsdt> + { + }; + +} // 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 <kstd/units> + +#include <acpi/acpi.hpp> +#include <acpi/data/xsdt.hpp> +#include <catch2/catch_test_macros.hpp> +#include <test_data/tables.hpp> + +#include <iterator> + +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<acpi::xsdt const *>(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<acpi::table_header *>(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/acpi/madt.cpp b/libs/acpi/acpi/madt.cpp deleted file mode 100644 index 6a62f07..0000000 --- a/libs/acpi/acpi/madt.cpp +++ /dev/null @@ -1,74 +0,0 @@ -#include <acpi/acpi.hpp> -#include <acpi/madt.hpp> - -#include <cstddef> -#include <cstdint> - -namespace acpi -{ - - auto madt::local_interrupt_controller_address() const noexcept -> std::uintptr_t - { - return static_cast<std::uintptr_t>(m_local_interrupt_controller_address); - } - - auto madt::flags() const noexcept -> std::uint32_t - { - return m_flags; - } - - auto madt::validate() const noexcept -> bool - { - return signature() == madt_table_signature && sdt::validate(); - } - - auto madt_entry::type() const noexcept -> enum type - { - return static_cast<enum type>(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<flags>(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<std::byte const *>(this); - base += sizeof(madt); - auto limit = reinterpret_cast<std::byte const *>(this); - limit += length().value; - return iterator{reinterpret_cast<madt_entry const *>(base), reinterpret_cast<madt_entry const *>(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/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 <kstd/units> -#include <acpi/checksum.hpp> +#include <acpi/common/checksum.hpp> #include <acpi/pointers.hpp> #include <bit> 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 <kstd/units> - -#include <acpi/acpi.hpp> -#include <acpi/sdt.hpp> - -#include <cstddef> -#include <cstdint> -#include <string_view> - -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<std::byte const *>(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 <acpi/acpi.hpp> - -#include <kstd/units> - -#include <acpi/table_type.hpp> - -#include <array> -#include <cstddef> -#include <cstdint> -#include <iterator> -#include <string_view> - -namespace acpi -{ - - template<typename EntryType> - 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<std::byte *>(m_entry); - decayed += m_entry->length(); - m_entry = std::bit_cast<pointer>(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<char, 4> m_signature; - std::uint32_t m_length; - std::uint8_t m_revision; - [[maybe_unused]] std::uint8_t m_checksum; - std::array<char, 6> m_oem_id; - std::array<char, 8> 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<rsdt_table_signature> - { - using type = sdt; - }; - -} // namespace acpi - -#endif 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/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..641db6a 100644 --- a/libs/acpi/test_data/tables.S +++ b/libs/acpi/test_data/tables.S @@ -11,5 +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 510cbda..e91f1a5 100644 --- a/libs/acpi/test_data/tables.hpp +++ b/libs/acpi/test_data/tables.hpp @@ -18,6 +18,8 @@ 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 |
