From 3a6cdfff45c9babf5421ef4ce2fed839fd1e50f4 Mon Sep 17 00:00:00 2001 From: Bananymous Date: Wed, 18 Dec 2024 18:30:45 +0200 Subject: [PATCH] Kernel: Fix ACPI namespace initialization Now _REG, _STA, _INI are called in the order my laptop expects them to be called. This was kinda weird because what uACPI was doing did not work. \_SB_.PCI0.LPC0.EC0_.BAT0._STA required \_SB_.PCI0.LPC0.EC0_._REG to be called \_SB_.PCI0.LPC0.EC0_._REG required \_SB_.PCI0._STA to be called Now I call all the _REG methods of a device after calling _STA/_INI and after performing the whole _STA/_INI sequence i call rest of missing _REG functions --- kernel/CMakeLists.txt | 1 - kernel/include/kernel/ACPI/AML/Namespace.h | 16 +++- kernel/include/kernel/ACPI/AML/Scope.h | 2 - kernel/kernel/ACPI/ACPI.cpp | 23 ++--- kernel/kernel/ACPI/AML/Namespace.cpp | 105 ++++++++++++++++++--- kernel/kernel/ACPI/AML/Node.cpp | 2 +- kernel/kernel/ACPI/AML/Scope.cpp | 65 ------------- 7 files changed, 112 insertions(+), 102 deletions(-) delete mode 100644 kernel/kernel/ACPI/AML/Scope.cpp diff --git a/kernel/CMakeLists.txt b/kernel/CMakeLists.txt index 17f27a5f..2272ec78 100644 --- a/kernel/CMakeLists.txt +++ b/kernel/CMakeLists.txt @@ -5,7 +5,6 @@ set(KERNEL_SOURCES kernel/ACPI/AML/Namespace.cpp kernel/ACPI/AML/Node.cpp kernel/ACPI/AML/OpRegion.cpp - kernel/ACPI/AML/Scope.cpp kernel/APIC.cpp kernel/BootInfo.cpp kernel/CPUID.cpp diff --git a/kernel/include/kernel/ACPI/AML/Namespace.h b/kernel/include/kernel/ACPI/AML/Namespace.h index 022c2335..a696e153 100644 --- a/kernel/include/kernel/ACPI/AML/Namespace.h +++ b/kernel/include/kernel/ACPI/AML/Namespace.h @@ -4,6 +4,7 @@ #include #include #include +#include #include #include @@ -19,11 +20,10 @@ namespace Kernel::ACPI::AML Namespace() = default; ~Namespace(); - static BAN::ErrorOr initialize_root_namespace(); + static BAN::ErrorOr prepare_root_namespace(); static Namespace& root_namespace(); - // this has to be called after initalizing ACPI namespace - BAN::ErrorOr initalize_op_regions(); + BAN::ErrorOr post_load_initialize(); BAN::ErrorOr parse(BAN::ConstByteSpan); @@ -31,7 +31,7 @@ namespace Kernel::ACPI::AML // returns empty scope if object already exited BAN::ErrorOr add_named_object(const Scope& scope, const NameString& name_string, Node&& node); - BAN::ErrorOr add_named_object(const Scope& scope, const NameString& name_string, Reference* reference); + BAN::ErrorOr add_alias(const Scope& scope, const NameString& name_string, Reference* reference); BAN::ErrorOr remove_named_object(const Scope& absolute_path); @@ -55,10 +55,16 @@ namespace Kernel::ACPI::AML BAN::ErrorOr opregion_call_reg(const Scope& scope, const Node& opregion); + BAN::ErrorOr evaluate_sta(const Scope& scope); + BAN::ErrorOr evaluate_ini(const Scope& scope); + + BAN::ErrorOr initialize_op_regions(); + private: - bool m_has_parsed_namespace { false }; + bool m_has_initialized_namespace { false }; BAN::HashMap m_named_objects; BAN::HashMap m_called_reg_bitmaps; + BAN::HashSet m_aliases; }; } diff --git a/kernel/include/kernel/ACPI/AML/Scope.h b/kernel/include/kernel/ACPI/AML/Scope.h index b4a65eca..c43ac318 100644 --- a/kernel/include/kernel/ACPI/AML/Scope.h +++ b/kernel/include/kernel/ACPI/AML/Scope.h @@ -37,8 +37,6 @@ namespace Kernel::ACPI::AML } }; - BAN::ErrorOr initialize_scope(const Scope&); - } namespace BAN diff --git a/kernel/kernel/ACPI/ACPI.cpp b/kernel/kernel/ACPI/ACPI.cpp index 80d2fd26..3b51292c 100644 --- a/kernel/kernel/ACPI/ACPI.cpp +++ b/kernel/kernel/ACPI/ACPI.cpp @@ -624,7 +624,7 @@ acpi_release_global_lock: { ASSERT(!m_namespace); - TRY(AML::Namespace::initialize_root_namespace()); + TRY(AML::Namespace::prepare_root_namespace()); m_namespace = &AML::Namespace::root_namespace(); if (auto ret = load_aml_tables("DSDT"_sv, false); ret.is_error()) @@ -663,22 +663,9 @@ acpi_release_global_lock: dprintln("Entered ACPI mode"); - dprintln("Calling opregion _REG methods"); + if (auto ret = m_namespace->post_load_initialize(); ret.is_error()) + dwarnln("Failed to initialize ACPI namespace: {}", ret.error()); - if (auto ret = m_namespace->initalize_op_regions(); ret.is_error()) - dwarnln("failed to call _REG methods: {}", ret.error()); - - dprintln("Initializing \\_SB"); - - // Initialize \\_SB - auto [sb_path, sb_obj] = TRY(m_namespace->find_named_object({}, TRY(AML::NameString::from_string("\\_SB_"_sv)))); - if (sb_obj && sb_obj->node.is_scope()) - if (auto ret = AML::initialize_scope(sb_path); ret.is_error()) - dwarnln("Failed to initialize \\_SB: {}", ret.error()); - - dprintln("Evaluating \\_PIC"); - - // Evaluate \\_PIC (mode) auto [pic_path, pic_obj] = TRY(m_namespace->find_named_object({}, TRY(AML::NameString::from_string("\\_PIC"_sv)))); if (pic_obj && pic_obj->node.type == AML::Node::Type::Method) { @@ -699,7 +686,7 @@ acpi_release_global_lock: TRY(AML::method_call(pic_path, pic_node, BAN::move(arguments))); } - dprintln("Initializing ACPI interrupts"); + dprintln("Evaluated \\_PIC({})", mode); uint8_t irq = fadt().sci_int; if (auto ret = InterruptController::get().reserve_irq(irq); ret.is_error()) @@ -772,6 +759,8 @@ acpi_release_global_lock: Process::create_kernel([](void*) { get().acpi_event_task(); }, nullptr); } + dprintln("Initialized ACPI interrupts"); + return {}; } diff --git a/kernel/kernel/ACPI/AML/Namespace.cpp b/kernel/kernel/ACPI/AML/Namespace.cpp index 475459c0..cb0dd5ad 100644 --- a/kernel/kernel/ACPI/AML/Namespace.cpp +++ b/kernel/kernel/ACPI/AML/Namespace.cpp @@ -4,6 +4,9 @@ #include #include +#define STA_PRESENT 0x01 +#define STA_FUNCTION 0x08 + #include namespace Kernel::ACPI::AML @@ -43,7 +46,7 @@ namespace Kernel::ACPI::AML delete reference; } - BAN::ErrorOr Namespace::initialize_root_namespace() + BAN::ErrorOr Namespace::prepare_root_namespace() { // https://uefi.org/htmlspecs/ACPI_Spec_6_4_html/05_ACPI_Software_Programming_Model/ACPI_Software_Programming_Model.html?highlight=predefined#predefined-root-namespaces @@ -88,15 +91,11 @@ namespace Kernel::ACPI::AML return BAN::Error::from_errno(EINVAL); } - const auto arg0 = BAN::StringView( - reinterpret_cast(args[0]->node.as.str_buf->bytes), - args[0]->node.as.str_buf->size - ); - Node result {}; result.type = Node::Type::Integer; result.as.integer.value = 0; + const auto arg0 = args[0]->node.as.str_buf->as_sv(); for (auto supported : s_supported_osi_strings) { if (supported != arg0) @@ -132,10 +131,92 @@ namespace Kernel::ACPI::AML return s_root_namespace; } - BAN::ErrorOr Namespace::initalize_op_regions() + BAN::ErrorOr Namespace::evaluate_sta(const Scope& scope) { - m_has_parsed_namespace = true; + auto [child_path, child_ref] = TRY(find_named_object(scope, TRY(NameString::from_string("_STA"_sv)))); + if (child_ref == nullptr) + return 0x0F; + return TRY(convert_node(TRY(evaluate_node(child_path, child_ref->node)), ConvInteger, sizeof(uint64_t))).as.integer.value; + } + BAN::ErrorOr Namespace::evaluate_ini(const Scope& scope) + { + auto [child_path, child_ref] = TRY(find_named_object(scope, TRY(NameString::from_string("_INI"_sv)))); + if (child_ref == nullptr) + return {}; + TRY(evaluate_node(child_path, child_ref->node)); + return {}; + } + + BAN::ErrorOr Namespace::post_load_initialize() + { + BAN::Vector to_init; + TRY(to_init.push_back({})); + + while (!to_init.empty()) + { + BAN::Vector to_init_next; + + for (const Scope& current : to_init) + { + TRY(for_each_child(current, + [&](const Scope& child_path, Reference* child_ref) -> BAN::Iteration + { + if (m_aliases.contains(child_path)) + return BAN::Iteration::Continue; + + switch (child_ref->node.type) + { + case Node::Type::Device: + case Node::Type::Processor: + case Node::Type::ThermalZone: + case Node::Type::PredefinedScope: + break; + default: + return BAN::Iteration::Continue; + } + + auto sta_ret = evaluate_sta(child_path); + if (sta_ret.is_error()) + return BAN::Iteration::Continue; + + if (sta_ret.value() & STA_PRESENT) + (void)evaluate_ini(child_path); + + if ((sta_ret.value() & STA_PRESENT) || (sta_ret.value() & STA_FUNCTION)) + { + auto child_path_copy = child_path.copy(); + if (!child_path_copy.is_error()) + (void)to_init_next.push_back(child_path_copy.release_value()); + } + + (void)for_each_child(current, + [&](const Scope& opregion_path, Reference* opregion_ref) -> BAN::Iteration + { + if (opregion_ref->node.type == Node::Type::OpRegion) + (void)opregion_call_reg(opregion_path, opregion_ref->node); + return BAN::Iteration::Continue; + } + ); + + return BAN::Iteration::Continue; + } + )); + } + + to_init = BAN::move(to_init_next); + } + + m_has_initialized_namespace = true; + + if (auto ret = initialize_op_regions(); ret.is_error()) + dwarnln("Failed to initialize all opregions: {}", ret.error()); + + return {}; + } + + BAN::ErrorOr Namespace::initialize_op_regions() + { for (const auto& [obj_path, obj_ref] : m_named_objects) { if (obj_ref->node.type != Node::Type::OpRegion) @@ -249,15 +330,15 @@ namespace Kernel::ACPI::AML TRY(m_named_objects.insert(TRY(resolved_path.copy()), reference)); - if (m_has_parsed_namespace && reference->node.type == Node::Type::OpRegion) + if (m_has_initialized_namespace && reference->node.type == Node::Type::OpRegion) (void)opregion_call_reg(resolved_path, reference->node); return resolved_path; } - BAN::ErrorOr Namespace::add_named_object(const Scope& scope, const NameString& name_string, Reference* reference) + BAN::ErrorOr Namespace::add_alias(const Scope& scope, const NameString& name_string, Reference* reference) { - dprintln_if(AML_DUMP_FUNCTION_CALLS, "add_named_object('{}', '{}', {})", scope, name_string, reference->node); + dprintln_if(AML_DUMP_FUNCTION_CALLS, "add_alias('{}', '{}', {})", scope, name_string, reference->node); auto resolved_path = TRY(resolve_path(scope, name_string)); if (m_named_objects.contains(resolved_path)) @@ -267,6 +348,8 @@ namespace Kernel::ACPI::AML reference->ref_count++; TRY(m_named_objects.insert(TRY(resolved_path.copy()), reference)); + TRY(m_aliases.insert(TRY(resolved_path.copy()))); + return resolved_path; } diff --git a/kernel/kernel/ACPI/AML/Node.cpp b/kernel/kernel/ACPI/AML/Node.cpp index 58258b43..437c388d 100644 --- a/kernel/kernel/ACPI/AML/Node.cpp +++ b/kernel/kernel/ACPI/AML/Node.cpp @@ -1622,7 +1622,7 @@ namespace Kernel::ACPI::AML return {}; } - TRY(Namespace::root_namespace().add_named_object(context.scope, object_name_string, source_ref)); + TRY(Namespace::root_namespace().add_alias(context.scope, object_name_string, source_ref)); return {}; } diff --git a/kernel/kernel/ACPI/AML/Scope.cpp b/kernel/kernel/ACPI/AML/Scope.cpp deleted file mode 100644 index ea7c3afb..00000000 --- a/kernel/kernel/ACPI/AML/Scope.cpp +++ /dev/null @@ -1,65 +0,0 @@ -#include -#include - -namespace Kernel::ACPI::AML -{ - - BAN::ErrorOr initialize_scope(const Scope& scope) - { - bool run_ini = true; - bool init_children = true; - - if (auto [sta_path, sta_obj] = TRY(Namespace::root_namespace().find_named_object(scope, TRY(NameString::from_string("_STA"_sv)), true)); sta_obj) - { - auto sta_result = TRY(evaluate_node(sta_path, sta_obj->node)); - if (sta_result.type != Node::Type::Integer) - { - dwarnln("Object {} evaluated to {}", sta_path, sta_result); - return BAN::Error::from_errno(EFAULT); - } - - run_ini = (sta_result.as.integer.value & 0x01); - init_children = run_ini || (sta_result.as.integer.value & 0x02); - } - - if (run_ini) - { - if (auto [ini_path, ini_obj] = TRY(Namespace::root_namespace().find_named_object(scope, TRY(NameString::from_string("_INI"_sv)), true)); ini_obj) - { - auto& ini_node = ini_obj->node; - - if (ini_node.type != Node::Type::Method) - { - dwarnln("Object {} is not a method", ini_path); - return BAN::Error::from_errno(EFAULT); - } - - if (ini_node.as.method.arg_count != 0) - { - dwarnln("Method {} takes {} arguments, expected 0", ini_path, ini_node.as.method.arg_count); - return BAN::Error::from_errno(EFAULT); - } - - TRY(method_call(ini_path, ini_node, {})); - } - } - - BAN::ErrorOr result {}; - if (init_children) - { - TRY(Namespace::root_namespace().for_each_child(scope, - [&result](const Scope& child_path, Reference* child) -> BAN::Iteration - { - if (!child->node.is_scope()) - return BAN::Iteration::Continue; - if (auto ret = initialize_scope(child_path); ret.is_error()) - result = ret.release_error(); - return BAN::Iteration::Continue; - } - )); - } - - return result; - } - -}