diff options
Diffstat (limited to 'kernel/src/acpi/manager.cpp')
| -rw-r--r-- | kernel/src/acpi/manager.cpp | 98 |
1 files changed, 98 insertions, 0 deletions
diff --git a/kernel/src/acpi/manager.cpp b/kernel/src/acpi/manager.cpp new file mode 100644 index 0000000..bb895fd --- /dev/null +++ b/kernel/src/acpi/manager.cpp @@ -0,0 +1,98 @@ +#include <kernel/acpi/manager.hpp> + +#include <kapi/memory.hpp> +#include <kapi/system.hpp> + +#include <acpi/acpi.hpp> + +#include <kstd/memory> +#include <kstd/print> + +#include <algorithm> +#include <cstddef> +#include <cstdint> +#include <ranges> +#include <string_view> + +namespace kernel::acpi +{ + + manager::manager(::acpi::rsdp const & sdp) + : m_sdp{&sdp} + { + if (!m_sdp->validate()) + { + kapi::system::panic("[OS:ACPI] Invalid RSDP signature!"); + } + + m_extended = m_sdp->revision() >= 2; + + if (m_extended) + { + if (!static_cast<::acpi::xsdp const *>(m_sdp)->validate()) + { + kapi::system::panic("[OS:ACPI] Invalid XSDP signature!"); + } + } + else + { + if (!m_sdp->validate()) + { + kapi::system::panic("[OS:ACPI] Invalid RSDP checksum!"); + } + } + + auto physical_address = kapi::memory::physical_address{m_sdp->table_address()}; + auto linear_address = kapi::memory::hhdm_to_linear(physical_address); + m_rsdt = static_cast<::acpi::table_header const *>(linear_address); + } + + auto manager::load_tables() -> bool + { + if (!::acpi::validate_checksum({reinterpret_cast<std::byte const *>(m_rsdt), m_rsdt->length().value})) + { + kapi::system::panic("[OS:ACPI] Invalid RSDT checksum!"); + } + + auto check_and_register_table = [&](auto table_address) -> void { + auto physical_table_address = kapi::memory::physical_address{reinterpret_cast<std::uintptr_t>(table_address)}; + auto mapped_table = kapi::memory::hhdm_to_linear(physical_table_address); + auto table = static_cast<::acpi::table_header const *>(mapped_table); + + if (!::acpi::validate_checksum({static_cast<std::byte const *>(mapped_table), table->length().value})) + { + kstd::println(kstd::print_sink::stderr, "[OS:ACPI] Invalid table checksum!"); + } + else + { + kstd::println("[OS:ACPI] Found '{}' ACPI table", table->signature()); + m_tables.emplace(table->signature(), table); + } + }; + + if (m_extended) + { + auto xsdt = static_cast<::acpi::xsdt const *>(m_rsdt); + std::ranges::for_each(*xsdt | std::views::transform([](auto const & entry) { return entry.address(); }), + check_and_register_table); + } + else + { + auto rsdt = static_cast<::acpi::rsdt const *>(m_rsdt); + std::ranges::for_each(*rsdt | std::views::transform([](auto const & entry) { return entry.address(); }), + check_and_register_table); + } + + return !m_tables.empty(); + } + + auto manager::get_table(std::string_view signature) -> kstd::observer_ptr<::acpi::table_header const> + { + if (m_tables.contains(signature)) + { + return kstd::make_observer(m_tables.at(signature)); + } + return nullptr; + } + +} // namespace kernel::acpi |
