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
This commit is contained in:
parent
c26e347e91
commit
3a6cdfff45
|
@ -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
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include <BAN/ByteSpan.h>
|
||||
#include <BAN/Function.h>
|
||||
#include <BAN/HashMap.h>
|
||||
#include <BAN/HashSet.h>
|
||||
#include <BAN/Iteration.h>
|
||||
|
||||
#include <kernel/ACPI/AML/Node.h>
|
||||
|
@ -19,11 +20,10 @@ namespace Kernel::ACPI::AML
|
|||
Namespace() = default;
|
||||
~Namespace();
|
||||
|
||||
static BAN::ErrorOr<void> initialize_root_namespace();
|
||||
static BAN::ErrorOr<void> prepare_root_namespace();
|
||||
static Namespace& root_namespace();
|
||||
|
||||
// this has to be called after initalizing ACPI namespace
|
||||
BAN::ErrorOr<void> initalize_op_regions();
|
||||
BAN::ErrorOr<void> post_load_initialize();
|
||||
|
||||
BAN::ErrorOr<void> parse(BAN::ConstByteSpan);
|
||||
|
||||
|
@ -31,7 +31,7 @@ namespace Kernel::ACPI::AML
|
|||
|
||||
// returns empty scope if object already exited
|
||||
BAN::ErrorOr<Scope> add_named_object(const Scope& scope, const NameString& name_string, Node&& node);
|
||||
BAN::ErrorOr<Scope> add_named_object(const Scope& scope, const NameString& name_string, Reference* reference);
|
||||
BAN::ErrorOr<Scope> add_alias(const Scope& scope, const NameString& name_string, Reference* reference);
|
||||
|
||||
BAN::ErrorOr<void> remove_named_object(const Scope& absolute_path);
|
||||
|
||||
|
@ -55,10 +55,16 @@ namespace Kernel::ACPI::AML
|
|||
|
||||
BAN::ErrorOr<void> opregion_call_reg(const Scope& scope, const Node& opregion);
|
||||
|
||||
BAN::ErrorOr<uint64_t> evaluate_sta(const Scope& scope);
|
||||
BAN::ErrorOr<void> evaluate_ini(const Scope& scope);
|
||||
|
||||
BAN::ErrorOr<void> initialize_op_regions();
|
||||
|
||||
private:
|
||||
bool m_has_parsed_namespace { false };
|
||||
bool m_has_initialized_namespace { false };
|
||||
BAN::HashMap<Scope, Reference*> m_named_objects;
|
||||
BAN::HashMap<Scope, uint32_t> m_called_reg_bitmaps;
|
||||
BAN::HashSet<Scope> m_aliases;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -37,8 +37,6 @@ namespace Kernel::ACPI::AML
|
|||
}
|
||||
};
|
||||
|
||||
BAN::ErrorOr<void> initialize_scope(const Scope&);
|
||||
|
||||
}
|
||||
|
||||
namespace BAN
|
||||
|
|
|
@ -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 {};
|
||||
}
|
||||
|
||||
|
|
|
@ -4,6 +4,9 @@
|
|||
#include <kernel/ACPI/AML/Node.h>
|
||||
#include <kernel/ACPI/Headers.h>
|
||||
|
||||
#define STA_PRESENT 0x01
|
||||
#define STA_FUNCTION 0x08
|
||||
|
||||
#include <ctype.h>
|
||||
|
||||
namespace Kernel::ACPI::AML
|
||||
|
@ -43,7 +46,7 @@ namespace Kernel::ACPI::AML
|
|||
delete reference;
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> Namespace::initialize_root_namespace()
|
||||
BAN::ErrorOr<void> 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<const char*>(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<void> Namespace::initalize_op_regions()
|
||||
BAN::ErrorOr<uint64_t> 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<void> 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<void> Namespace::post_load_initialize()
|
||||
{
|
||||
BAN::Vector<Scope> to_init;
|
||||
TRY(to_init.push_back({}));
|
||||
|
||||
while (!to_init.empty())
|
||||
{
|
||||
BAN::Vector<Scope> 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<void> 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<Scope> Namespace::add_named_object(const Scope& scope, const NameString& name_string, Reference* reference)
|
||||
BAN::ErrorOr<Scope> 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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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 {};
|
||||
}
|
||||
|
|
|
@ -1,65 +0,0 @@
|
|||
#include <kernel/ACPI/AML/Namespace.h>
|
||||
#include <kernel/ACPI/AML/Scope.h>
|
||||
|
||||
namespace Kernel::ACPI::AML
|
||||
{
|
||||
|
||||
BAN::ErrorOr<void> 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<void> 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;
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue