Kernel: Rework AML namespace and object hierarchy

Remove tree-like structure from AML. This allows more spec compliant
parsing of named objects inside not yet declared devices.

This also allows AML to be run thread safely. All object adds/removes
are now guarded by a mutex.
This commit is contained in:
2024-04-16 16:23:12 +03:00
parent b6587b32b9
commit f1b2d7530d
7 changed files with 179 additions and 143 deletions

View File

@@ -42,11 +42,13 @@ namespace Kernel::ACPI::AML
AML_DEBUG_PRINT("Device ");
name.debug_print();
AML_DEBUG_PRINTLN(" {");
for (const auto& [name, object] : objects)
{
object->debug_print(indent + 1);
AML_DEBUG_PRINTLN("");
}
Namespace::root_namespace()->for_each_child(scope,
[&](const auto&, const auto& child)
{
child->debug_print(indent + 1);
AML_DEBUG_PRINTLN("");
}
);
AML_DEBUG_PRINT_INDENT(indent);
AML_DEBUG_PRINT("}");
}

View File

@@ -59,7 +59,7 @@ namespace Kernel::ACPI::AML
if (!method_scope.has_value())
return ParseResult::Failure;
method->term_list = method_pkg.value();
method->scope = method_scope.release_value();
method->scope = AML::NameString(method_scope.release_value());
#if AML_DEBUG_LEVEL >= 2
method->debug_print(0);

View File

@@ -36,6 +36,14 @@ namespace Kernel::ACPI::AML
aml_data = aml_data.slice(4);
}
BAN::StringView sv() const
{
size_t len = 4;
while (len > 0 && chars[len - 1] == '_')
len--;
return BAN::StringView(chars, len);
}
static BAN::Optional<NameSeg> parse(BAN::ConstByteSpan& aml_data)
{
if (aml_data.size() < 4)

View File

@@ -1,5 +1,6 @@
#pragma once
#include <BAN/HashMap.h>
#include <kernel/ACPI/AML/Scope.h>
#include <kernel/ACPI/Headers.h>
#include <kernel/Lock/Mutex.h>
@@ -11,12 +12,34 @@ namespace Kernel::ACPI::AML
{
static BAN::RefPtr<AML::Namespace> root_namespace();
template<typename F>
static void for_each_child(const AML::NameString& scope, const F& callback)
{
auto canonical_path = root_namespace()->resolve_path({}, scope);
ASSERT(canonical_path.has_value());
for (auto& [path, child] : root_namespace()->m_objects)
{
if (path.size() < canonical_path->size() + 1)
continue;
if (path[canonical_path->size()] != '.')
continue;
if (path.sv().substring(0, canonical_path->size()) != canonical_path->sv())
continue;
if (path.sv().substring(canonical_path->size() + 1).contains('.'))
continue;
callback(path, child);
}
}
Namespace(NameSeg name) : AML::Scope(Node::Type::Namespace, name) {}
static BAN::RefPtr<AML::Namespace> create_root_namespace();
bool parse(const SDTHeader& header);
BAN::Optional<AML::NameString> resolve_path(const AML::NameString& relative_base, const AML::NameString& relative_path);
void debug_print(int indent) const override;
BAN::Optional<BAN::String> resolve_path(const AML::NameString& relative_base, const AML::NameString& relative_path, bool allow_nonexistent = false);
// Find an object in the namespace. Returns nullptr if the object is not found.
BAN::RefPtr<NamedObject> find_object(const AML::NameString& relative_base, const AML::NameString& relative_path);
@@ -26,6 +49,10 @@ namespace Kernel::ACPI::AML
// Remove an object from the namespace. Returns false if the object could not be removed.
bool remove_named_object(const AML::NameString& absolute_path);
private:
BAN::HashMap<BAN::String, BAN::RefPtr<NamedObject>> m_objects;
mutable Mutex m_object_mutex;
};
}

View File

@@ -1,6 +1,5 @@
#pragma once
#include <BAN/HashMap.h>
#include <kernel/ACPI/AML/NamedObject.h>
#include <kernel/ACPI/AML/Names.h>
@@ -9,7 +8,6 @@ namespace Kernel::ACPI::AML
struct Scope : public AML::NamedObject
{
BAN::HashMap<NameSeg, BAN::RefPtr<NamedObject>> objects;
AML::NameString scope;
Scope(Node::Type type, NameSeg name)
@@ -19,7 +17,6 @@ namespace Kernel::ACPI::AML
virtual bool is_scope() const override { return true; }
static ParseResult parse(ParseContext& context);
virtual void debug_print(int indent) const override;
protected:
ParseResult enter_context_and_parse_term_list(ParseContext& outer_context, const AML::NameString& name, BAN::ConstByteSpan aml_data);