diff options
| author | Felix Morgner <felix.morgner@ost.ch> | 2026-04-10 17:39:14 +0200 |
|---|---|---|
| committer | Felix Morgner <felix.morgner@ost.ch> | 2026-04-10 17:39:14 +0200 |
| commit | c3f7b747f02a79b34ed914c54ce74be973b17af1 (patch) | |
| tree | 79526c34b3768562f3aa90f69a476cf504ebccc4 /libs/acpi | |
| parent | 5a6b6ab376e67b173ef36f831445ccba7e86e038 (diff) | |
| download | teachos-c3f7b747f02a79b34ed914c54ce74be973b17af1.tar.xz teachos-c3f7b747f02a79b34ed914c54ce74be973b17af1.zip | |
kapi: extract ACPI functionality to libs
Diffstat (limited to 'libs/acpi')
| -rw-r--r-- | libs/acpi/CMakeLists.txt | 29 | ||||
| -rw-r--r-- | libs/acpi/acpi/acpi.hpp | 10 | ||||
| -rw-r--r-- | libs/acpi/acpi/checksum.cpp | 19 | ||||
| -rw-r--r-- | libs/acpi/acpi/checksum.hpp | 20 | ||||
| -rw-r--r-- | libs/acpi/acpi/madt.cpp | 68 | ||||
| -rw-r--r-- | libs/acpi/acpi/madt.hpp | 92 | ||||
| -rw-r--r-- | libs/acpi/acpi/pointers.cpp | 55 | ||||
| -rw-r--r-- | libs/acpi/acpi/pointers.hpp | 72 | ||||
| -rw-r--r-- | libs/acpi/acpi/sdt.cpp | 51 | ||||
| -rw-r--r-- | libs/acpi/acpi/sdt.hpp | 119 | ||||
| -rw-r--r-- | libs/acpi/acpi/table_type.hpp | 17 |
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 |
