From 17871bb3cac4e6724851bbf2c69d7001a770a668 Mon Sep 17 00:00:00 2001 From: Bananymous Date: Fri, 12 Apr 2024 12:39:46 +0300 Subject: [PATCH] Kernel: Fix ACPI namespace initialization ACPI spec says that only SSDTS with unique OEM table IDs are to be loaded. Add loading of ACPI 1.0 PSDTs --- kernel/kernel/ACPI/AML.cpp | 61 ++++++++++++++++++++++------ kernel/kernel/ACPI/AML/Namespace.cpp | 2 - 2 files changed, 49 insertions(+), 14 deletions(-) diff --git a/kernel/kernel/ACPI/AML.cpp b/kernel/kernel/ACPI/AML.cpp index b71863e8f1..6637c35981 100644 --- a/kernel/kernel/ACPI/AML.cpp +++ b/kernel/kernel/ACPI/AML.cpp @@ -6,34 +6,71 @@ namespace Kernel::ACPI { + // https://uefi.org/htmlspecs/ACPI_Spec_6_4_html/05_ACPI_Software_Programming_Model/ACPI_Software_Programming_Model.html#secondary-system-description-table-ssdt + // https://uefi.org/htmlspecs/ACPI_Spec_6_4_html/05_ACPI_Software_Programming_Model/ACPI_Software_Programming_Model.html#persistent-system-description-table-psdt + static bool load_all_unique(AML::Namespace& ns, BAN::StringView signature) + { + // Only SSDT and PSDT that have unique OEM Table ID are loaded in order they appear in the RSDT/XSDT + BAN::Vector loaded_oem_table_ids; + + for (uint32_t i = 0;; i++) + { + auto* header = ACPI::ACPI::get().get_header(signature, i); + if (!header) + break; + + bool need_to_parse = true; + for (uint64_t id : loaded_oem_table_ids) + { + if (id == header->oem_table_id) + { + need_to_parse = false; + break; + } + } + + if (!need_to_parse) + { + dprintln("Skipping {}{} ({} bytes)", signature, i, header->length); + continue; + } + + dprintln("Parsing {}{} ({} bytes)", signature, i, header->length); + if (!ns.parse(*header)) + { + dwarnln("Failed to parse {}", signature); + return false; + } + + MUST(loaded_oem_table_ids.push_back(header->oem_table_id)); + } + + return true; + } + BAN::RefPtr AML::initialize_namespace() { auto ns = AML::Namespace::create_root_namespace(); - // Parse DSDT + // https://uefi.org/htmlspecs/ACPI_Spec_6_4_html/05_ACPI_Software_Programming_Model/ACPI_Software_Programming_Model.html#differentiated-system-description-table-dsdt auto* dsdt = ACPI::ACPI::get().get_header("DSDT", 0); if (!dsdt) { dwarnln("Failed to get DSDT"); return {}; } + dprintln("Parsing DSDT ({} bytes)", dsdt->length); if (!ns->parse(*dsdt)) { dwarnln("Failed to parse DSDT"); return {}; } - for (uint32_t i = 0;; i++) - { - auto* ssdt = ACPI::ACPI::get().get_header("SSDT", i); - if (!ssdt) - break; - if (!ns->parse(*ssdt)) - { - dwarnln("Failed to parse SSDT"); - return {}; - } - } + if (!load_all_unique(*ns, "SSDT")) + return {}; + + if (!load_all_unique(*ns, "PSDT")) + return {}; #if AML_DEBUG_LEVEL >= 1 ns->debug_print(0); diff --git a/kernel/kernel/ACPI/AML/Namespace.cpp b/kernel/kernel/ACPI/AML/Namespace.cpp index 72b12c94e4..3d702e77eb 100644 --- a/kernel/kernel/ACPI/AML/Namespace.cpp +++ b/kernel/kernel/ACPI/AML/Namespace.cpp @@ -225,8 +225,6 @@ namespace Kernel::ACPI { ASSERT(this == s_root_namespace.ptr()); - dprintln("Parsing {}, {} bytes of AML", header, header.length); - AML::ParseContext context; context.scope = AML::NameString("\\"sv); context.aml_data = BAN::ConstByteSpan(reinterpret_cast(&header), header.length).slice(sizeof(header));