aboutsummaryrefslogtreecommitdiff
path: root/kernel/src/acpi
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/src/acpi')
-rw-r--r--kernel/src/acpi/manager.cpp98
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