aboutsummaryrefslogtreecommitdiff
path: root/libs/acpi
diff options
context:
space:
mode:
authorFelix Morgner <felix.morgner@ost.ch>2026-04-10 17:39:14 +0200
committerFelix Morgner <felix.morgner@ost.ch>2026-04-10 17:39:14 +0200
commitc3f7b747f02a79b34ed914c54ce74be973b17af1 (patch)
tree79526c34b3768562f3aa90f69a476cf504ebccc4 /libs/acpi
parent5a6b6ab376e67b173ef36f831445ccba7e86e038 (diff)
downloadteachos-c3f7b747f02a79b34ed914c54ce74be973b17af1.tar.xz
teachos-c3f7b747f02a79b34ed914c54ce74be973b17af1.zip
kapi: extract ACPI functionality to libs
Diffstat (limited to 'libs/acpi')
-rw-r--r--libs/acpi/CMakeLists.txt29
-rw-r--r--libs/acpi/acpi/acpi.hpp10
-rw-r--r--libs/acpi/acpi/checksum.cpp19
-rw-r--r--libs/acpi/acpi/checksum.hpp20
-rw-r--r--libs/acpi/acpi/madt.cpp68
-rw-r--r--libs/acpi/acpi/madt.hpp92
-rw-r--r--libs/acpi/acpi/pointers.cpp55
-rw-r--r--libs/acpi/acpi/pointers.hpp72
-rw-r--r--libs/acpi/acpi/sdt.cpp51
-rw-r--r--libs/acpi/acpi/sdt.hpp119
-rw-r--r--libs/acpi/acpi/table_type.hpp17
11 files changed, 552 insertions, 0 deletions
diff --git a/libs/acpi/CMakeLists.txt b/libs/acpi/CMakeLists.txt
new file mode 100644
index 0000000..c6e63b9
--- /dev/null
+++ b/libs/acpi/CMakeLists.txt
@@ -0,0 +1,29 @@
+add_library("acpi" STATIC)
+add_library("libs::acpi" ALIAS "acpi")
+
+target_include_directories("acpi" PUBLIC
+ "${CMAKE_CURRENT_SOURCE_DIR}"
+)
+
+file(GLOB_RECURSE ACPI_HEADERS
+ RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
+ "acpi/*.hpp"
+)
+
+target_sources("acpi" PRIVATE
+ "acpi/checksum.cpp"
+ "acpi/madt.cpp"
+ "acpi/pointers.cpp"
+ "acpi/sdt.cpp"
+)
+
+target_sources("acpi" PUBLIC
+ FILE_SET HEADERS
+ BASE_DIRS "acpi"
+ FILES
+ ${ACPI_HEADERS}
+)
+
+target_link_libraries("acpi" PUBLIC
+ "libs::kstd"
+)
diff --git a/libs/acpi/acpi/acpi.hpp b/libs/acpi/acpi/acpi.hpp
new file mode 100644
index 0000000..fb358cc
--- /dev/null
+++ b/libs/acpi/acpi/acpi.hpp
@@ -0,0 +1,10 @@
+#ifndef ACPI_ACPI_HPP
+#define ACPI_ACPI_HPP
+
+#include <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
+
+#endif
diff --git a/libs/acpi/acpi/checksum.cpp b/libs/acpi/acpi/checksum.cpp
new file mode 100644
index 0000000..56275c8
--- /dev/null
+++ b/libs/acpi/acpi/checksum.cpp
@@ -0,0 +1,19 @@
+#include <acpi/checksum.hpp>
+
+#include <algorithm>
+#include <cstddef>
+#include <cstdint>
+#include <span>
+
+namespace acpi
+{
+
+ auto validate_checksum(std::span<std::byte const> data) -> bool
+ {
+ auto sum = std::ranges::fold_left(data, std::uint8_t{}, [](auto acc, auto byte) {
+ return static_cast<std::uint8_t>(acc + static_cast<std::uint8_t>(byte));
+ });
+ return sum == 0;
+ }
+
+} // namespace acpi
diff --git a/libs/acpi/acpi/checksum.hpp b/libs/acpi/acpi/checksum.hpp
new file mode 100644
index 0000000..a92c242
--- /dev/null
+++ b/libs/acpi/acpi/checksum.hpp
@@ -0,0 +1,20 @@
+#ifndef ACPI_CHECKSUM_HPP
+#define ACPI_CHECKSUM_HPP
+
+// IWYU pragma: private, include <acpi/acpi.hpp>
+
+#include <cstddef>
+#include <span>
+
+namespace acpi
+{
+
+ //! Validate and ACPI entity checksum.
+ //!
+ //! @param data The data to validate the checksum of.
+ //! @return true iff. the checksum is valid, false otherwise.
+ auto validate_checksum(std::span<std::byte const> data) -> bool;
+
+} // namespace acpi
+
+#endif
diff --git a/libs/acpi/acpi/madt.cpp b/libs/acpi/acpi/madt.cpp
new file mode 100644
index 0000000..40289cf
--- /dev/null
+++ b/libs/acpi/acpi/madt.cpp
@@ -0,0 +1,68 @@
+#include <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
new file mode 100644
index 0000000..f680430
--- /dev/null
+++ b/libs/acpi/acpi/madt.hpp
@@ -0,0 +1,92 @@
+#ifndef ACPI_ACPI_MADT_HPP
+#define ACPI_ACPI_MADT_HPP
+
+// IWYU pragma: private, include <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
new file mode 100644
index 0000000..b206cc6
--- /dev/null
+++ b/libs/acpi/acpi/pointers.cpp
@@ -0,0 +1,55 @@
+#include <kstd/units>
+
+#include <acpi/checksum.hpp>
+#include <acpi/pointers.hpp>
+
+#include <bit>
+#include <cstddef>
+#include <cstdint>
+#include <string_view>
+
+namespace acpi
+{
+
+ auto rsdp::oem_id() const noexcept -> std::string_view
+ {
+ return {m_oem_id.data(), m_oem_id.size()};
+ }
+
+ auto rsdp::revision() const noexcept -> std::uint8_t
+ {
+ return m_revision;
+ }
+
+ auto rsdp::signature() const noexcept -> std::string_view
+ {
+ return {m_signature.data(), m_signature.size()};
+ }
+
+ auto rsdp::table_address() const noexcept -> std::uintptr_t
+ {
+ auto raw = std::bit_cast<std::uint32_t>(m_rsdt_address);
+ return static_cast<std::uintptr_t>(raw);
+ }
+
+ auto rsdp::validate() const noexcept -> bool
+ {
+ return validate_checksum({reinterpret_cast<std::byte const *>(this), sizeof(rsdp)});
+ }
+
+ auto xsdp::length() const noexcept -> kstd::units::bytes
+ {
+ return kstd::units::bytes{m_length};
+ }
+
+ auto xsdp::table_address() const noexcept -> std::uintptr_t
+ {
+ return std::bit_cast<std::uintptr_t>(m_xsdt_address);
+ }
+
+ auto xsdp::validate() const noexcept -> bool
+ {
+ return validate_checksum({reinterpret_cast<std::byte const *>(this), m_length});
+ }
+
+} // namespace acpi
diff --git a/libs/acpi/acpi/pointers.hpp b/libs/acpi/acpi/pointers.hpp
new file mode 100644
index 0000000..5771e7d
--- /dev/null
+++ b/libs/acpi/acpi/pointers.hpp
@@ -0,0 +1,72 @@
+#ifndef ACPI_POINTERS_HPP
+#define ACPI_POINTERS_HPP
+
+// IWYU pragma: private, include <acpi/acpi.hpp>
+
+#include <kstd/units>
+
+#include <array>
+#include <cstddef>
+#include <cstdint>
+#include <string_view>
+
+namespace acpi
+{
+
+ //! A pointer to the Root System Description Table.
+ struct [[gnu::packed]] rsdp
+ {
+ //! Get the ID of the OEM, usually a vendor name.
+ [[nodiscard]] auto oem_id() const noexcept -> std::string_view;
+
+ //! Get the revision of the ACPI Root System Description Table.
+ //!
+ //! @note Revisions greater or equal to two indicate that the system uses the Extended System Description Table, and
+ //! as such that table should be use to query information.
+ [[nodiscard]] auto revision() const noexcept -> std::uint8_t;
+
+ //! Get the signature of this pointer.
+ //!
+ //! A valid RSDP must always carry the signature "RSD PTR ".
+ [[nodiscard]] auto signature() const noexcept -> std::string_view;
+
+ //! Get the physical address of the pointed-to Root System Description Table.
+ [[nodiscard]] auto table_address() const noexcept -> std::uintptr_t;
+
+ //! Validate the checksum of this RSDP.
+ //!
+ //! @return @p true iff. the checksum of this RSDP is valid, @p false otherwise.
+ [[nodiscard]] auto validate() const noexcept -> bool;
+
+ private:
+ std::array<char, 8> m_signature;
+ [[maybe_unused]] std::uint8_t m_checksum;
+ std::array<char, 6> m_oem_id;
+ std::uint8_t m_revision;
+ std::array<std::byte, 4> m_rsdt_address;
+ };
+
+ //! A pointer to the Extended System Description Table.
+ struct [[gnu::packed]] xsdp : rsdp
+ {
+ //! Get the length of the data contained in this pointer.
+ [[nodiscard]] auto length() const noexcept -> kstd::units::bytes;
+
+ //! Get the physical address of the pointed-to Extended System Description Table.
+ [[nodiscard]] auto table_address() const noexcept -> std::uintptr_t;
+
+ //! Validate the checksum of this XSDP.
+ //!
+ //! @return @p true iff. the checksum of this RSDP is valid, @p false otherwise.
+ [[nodiscard]] auto validate() const noexcept -> bool;
+
+ private:
+ std::uint32_t m_length;
+ std::array<std::byte, 8> m_xsdt_address;
+ [[maybe_unused]] std::uint8_t m_extended_checksum;
+ [[maybe_unused]] std::array<std::byte, 3> m_reserved;
+ };
+
+} // namespace acpi
+
+#endif
diff --git a/libs/acpi/acpi/sdt.cpp b/libs/acpi/acpi/sdt.cpp
new file mode 100644
index 0000000..c2b9d68
--- /dev/null
+++ b/libs/acpi/acpi/sdt.cpp
@@ -0,0 +1,51 @@
+#include <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
new file mode 100644
index 0000000..9e5ec89
--- /dev/null
+++ b/libs/acpi/acpi/sdt.hpp
@@ -0,0 +1,119 @@
+#ifndef ACPI_SDT_HPP
+#define ACPI_SDT_HPP
+
+// IWYU pragma: private, include <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/acpi/table_type.hpp b/libs/acpi/acpi/table_type.hpp
new file mode 100644
index 0000000..7fdd7e3
--- /dev/null
+++ b/libs/acpi/acpi/table_type.hpp
@@ -0,0 +1,17 @@
+#ifndef ACPI_TABLE_TYPE_HPP
+#define ACPI_TABLE_TYPE_HPP
+
+// IWYU pragma: private, include <acpi/acpi.hpp>
+
+namespace acpi
+{
+
+ template<char const *>
+ struct table_type;
+
+ template<char const * Signature>
+ using table_type_t = typename table_type<Signature>::type;
+
+} // namespace acpi
+
+#endif