aboutsummaryrefslogtreecommitdiff
path: root/libs/acpi
diff options
context:
space:
mode:
Diffstat (limited to 'libs/acpi')
-rw-r--r--libs/acpi/CMakeLists.txt67
-rw-r--r--libs/acpi/acpi/acpi.hpp12
-rw-r--r--libs/acpi/acpi/common/basic_table.hpp35
-rw-r--r--libs/acpi/acpi/common/checksum.cpp (renamed from libs/acpi/acpi/checksum.cpp)2
-rw-r--r--libs/acpi/acpi/common/checksum.hpp (renamed from libs/acpi/acpi/checksum.hpp)0
-rw-r--r--libs/acpi/acpi/common/table_header.cpp130
-rw-r--r--libs/acpi/acpi/common/table_header.hpp56
-rw-r--r--libs/acpi/acpi/common/table_header.test.cpp58
-rw-r--r--libs/acpi/acpi/common/table_signature.hpp17
-rw-r--r--libs/acpi/acpi/common/table_type.hpp (renamed from libs/acpi/acpi/table_type.hpp)4
-rw-r--r--libs/acpi/acpi/common/vla_table.hpp115
-rw-r--r--libs/acpi/acpi/data/madt.cpp112
-rw-r--r--libs/acpi/acpi/data/madt.hpp117
-rw-r--r--libs/acpi/acpi/data/madt.test.cpp55
-rw-r--r--libs/acpi/acpi/data/rsdt.cpp38
-rw-r--r--libs/acpi/acpi/data/rsdt.hpp42
-rw-r--r--libs/acpi/acpi/data/rsdt.test.cpp46
-rw-r--r--libs/acpi/acpi/data/xsdt.cpp38
-rw-r--r--libs/acpi/acpi/data/xsdt.hpp42
-rw-r--r--libs/acpi/acpi/data/xsdt.test.cpp46
-rw-r--r--libs/acpi/acpi/madt.cpp68
-rw-r--r--libs/acpi/acpi/madt.hpp92
-rw-r--r--libs/acpi/acpi/pointers.cpp6
-rw-r--r--libs/acpi/acpi/pointers.test.cpp29
-rw-r--r--libs/acpi/acpi/sdt.cpp51
-rw-r--r--libs/acpi/acpi/sdt.hpp119
-rw-r--r--libs/acpi/test_data/basic_madt.asl29
-rw-r--r--libs/acpi/test_data/basic_rsdp.asl16
-rw-r--r--libs/acpi/test_data/basic_rsdt.asl26
-rw-r--r--libs/acpi/test_data/basic_xsdt.asl26
-rw-r--r--libs/acpi/test_data/table_header.asl9
-rw-r--r--libs/acpi/test_data/tables.S17
-rw-r--r--libs/acpi/test_data/tables.hpp28
33 files changed, 1204 insertions, 344 deletions
diff --git a/libs/acpi/CMakeLists.txt b/libs/acpi/CMakeLists.txt
index c6e63b9..55d5b54 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")
@@ -11,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
@@ -27,3 +37,54 @@ target_sources("acpi" PUBLIC
target_link_libraries("acpi" PUBLIC
"libs::kstd"
)
+
+if(NOT CMAKE_CROSSCOMPILING)
+ find_program(IASL_EXE NAMES "iasl" REQUIRED)
+
+ set(TEST_TABLES
+ "basic_madt"
+ "basic_rsdt"
+ "basic_rsdp"
+ "basic_xsdt"
+ "table_header"
+ )
+
+ 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/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"
+ )
+
+ target_include_directories("acpi_tests" PRIVATE
+ "${CMAKE_CURRENT_BINARY_DIR}/test_data"
+ )
+
+ 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/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/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 <acpi/acpi.hpp>
+
+#include <kstd/ext/bitfield_enum>
+#include <kstd/os/error.hpp>
+#include <kstd/units>
+
+#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>
+#include <type_traits>
+
+namespace acpi
+{
+
+ 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
+ {
+ 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<typename EntryType>
+ [[nodiscard]] auto as() const -> EntryType const &
+ {
+ if (type() != EntryType::this_type)
+ {
+ kstd::os::panic("Invalid cast");
+ }
+ return reinterpret_cast<EntryType const &>(*this);
+ }
+
+ private:
+ std::array<std::byte, 2> m_data{};
+ };
+
+ //! The Multiple APIC Description Table (MADT)
+ struct madt : vla_table<madt_entry, madt>
+ {
+ //! 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<typename EntryType>
+ [[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<EntryType>(); });
+ }
+
+ private:
+ std::array<std::byte, 8> 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<std::byte, 6> m_data{};
+ };
+
+} // namespace acpi
+
+template<>
+struct kstd::ext::is_bitfield_enum<enum acpi::processor_local_apic_entry::flags> : 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..6795499
--- /dev/null
+++ b/libs/acpi/acpi/data/madt.test.cpp
@@ -0,0 +1,55 @@
+#include <kstd/units>
+
+#include <acpi/data/madt.hpp>
+#include <catch2/catch_test_macros.hpp>
+#include <test_data/tables.hpp>
+
+#include <iterator>
+
+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<acpi::madt const *>(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().value == 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<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 40289cf..0000000
--- a/libs/acpi/acpi/madt.cpp
+++ /dev/null
@@ -1,68 +0,0 @@
-#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_entry::type() const noexcept -> types
- {
- return static_cast<types>(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/madt.hpp b/libs/acpi/acpi/madt.hpp
deleted file mode 100644
index f680430..0000000
--- a/libs/acpi/acpi/madt.hpp
+++ /dev/null
@@ -1,92 +0,0 @@
-#ifndef ACPI_ACPI_MADT_HPP
-#define ACPI_ACPI_MADT_HPP
-
-// IWYU pragma: private, include <acpi/acpi.hpp>
-
-#include <kstd/ext/bitfield_enum>
-#include <kstd/units>
-
-#include <acpi/sdt.hpp>
-#include <acpi/table_type.hpp>
-
-#include <cstddef>
-#include <cstdint>
-#include <type_traits>
-
-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<madt_entry const>;
- 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<madt_table_signature>
- {
- using type = madt;
- };
-
-} // namespace acpi
-
-template<>
-struct kstd::ext::is_bitfield_enum<acpi::processor_local_apic::flags> : std::true_type
-{
-};
-
-#endif
diff --git a/libs/acpi/acpi/pointers.cpp b/libs/acpi/acpi/pointers.cpp
index b206cc6..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>
@@ -34,7 +34,7 @@ namespace acpi
auto rsdp::validate() const noexcept -> bool
{
- return validate_checksum({reinterpret_cast<std::byte const *>(this), sizeof(rsdp)});
+ return signature() == "RSD PTR " && validate_checksum({reinterpret_cast<std::byte const *>(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<std::byte const *>(this), m_length});
+ return signature() == "RSD PTR " && validate_checksum({reinterpret_cast<std::byte const *>(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 <acpi/pointers.hpp>
+#include <catch2/catch_test_macros.hpp>
+
+#include <array>
+#include <bit>
+#include <cstddef>
+
+SCENARIO("ACPI root pointer parsing", "[acpi]")
+{
+ GIVEN("A null-filled pointer")
+ {
+ auto data = std::array<std::byte, sizeof(acpi::rsdp)>{};
+
+ WHEN("parsing the data")
+ {
+ auto rsdp = std::bit_cast<acpi::rsdp>(data);
+
+ THEN("the signature is invalid")
+ {
+ REQUIRE(rsdp.signature() != "RSD PTR ");
+ }
+
+ THEN("validate returns false")
+ {
+ REQUIRE_FALSE(rsdp.validate());
+ }
+ }
+ }
+}
diff --git a/libs/acpi/acpi/sdt.cpp b/libs/acpi/acpi/sdt.cpp
deleted file mode 100644
index c2b9d68..0000000
--- a/libs/acpi/acpi/sdt.cpp
+++ /dev/null
@@ -1,51 +0,0 @@
-#include <kstd/units>
-
-#include <acpi/sdt.hpp>
-
-#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()};
- }
-
-} // namespace acpi
diff --git a/libs/acpi/acpi/sdt.hpp b/libs/acpi/acpi/sdt.hpp
deleted file mode 100644
index 9e5ec89..0000000
--- a/libs/acpi/acpi/sdt.hpp
+++ /dev/null
@@ -1,119 +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==(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<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_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_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/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/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
new file mode 100644
index 0000000..641db6a
--- /dev/null
+++ b/libs/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/test_data/tables.hpp b/libs/acpi/test_data/tables.hpp
new file mode 100644
index 0000000..e91f1a5
--- /dev/null
+++ b/libs/acpi/test_data/tables.hpp
@@ -0,0 +1,28 @@
+#ifndef ACPI_TEST_DATA_TABLES_HPP
+#define ACPI_TEST_DATA_TABLES_HPP
+
+#include <cstddef>
+#include <span>
+
+#define TABLE(name) \
+ extern "C" std::byte const name##_start; \
+ extern "C" std::byte const name##_end; \
+ auto inline name()->std::span<std::byte const> \
+ { \
+ 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