forked from Bananymous/banan-os
Kernel: Start working on AML method evaluations
Also fix namespace lookup and scope creations.
This commit is contained in:
@@ -93,10 +93,10 @@ namespace Kernel::ACPI
|
||||
if (!name_string.has_value())
|
||||
return ParseResult::Failure;
|
||||
|
||||
auto op_region = context.root_namespace->find_object(context.scope.span(), name_string.value());
|
||||
auto op_region = context.root_namespace->find_object(context.scope, name_string.value());
|
||||
if (!op_region || op_region->type != AML::Node::Type::OpRegion)
|
||||
{
|
||||
AML_ERROR("Field RegionName does not name a valid OpRegion");
|
||||
AML_ERROR("FieldOp: {} does not name a valid OpRegion", name_string.value());
|
||||
return ParseResult::Failure;
|
||||
}
|
||||
|
||||
@@ -121,7 +121,7 @@ namespace Kernel::ACPI
|
||||
|
||||
NameString element_name;
|
||||
MUST(element_name.path.push_back(element->name));
|
||||
if (!context.root_namespace->add_named_object(context.scope.span(), element_name, element))
|
||||
if (!context.root_namespace->add_named_object(context, element_name, element))
|
||||
return ParseResult::Failure;
|
||||
|
||||
#if AML_DEBUG_LEVEL >= 2
|
||||
@@ -158,7 +158,7 @@ namespace Kernel::ACPI
|
||||
auto index_field_element_name = NameString::parse(field_pkg);
|
||||
if (!index_field_element_name.has_value())
|
||||
return ParseResult::Failure;
|
||||
auto index_field_element = context.root_namespace->find_object(context.scope.span(), index_field_element_name.value());
|
||||
auto index_field_element = context.root_namespace->find_object(context.scope, index_field_element_name.value());
|
||||
if (!index_field_element || index_field_element->type != AML::Node::Type::FieldElement)
|
||||
{
|
||||
AML_ERROR("IndexField IndexName does not name a valid FieldElement");
|
||||
@@ -168,7 +168,7 @@ namespace Kernel::ACPI
|
||||
auto data_field_element_name = NameString::parse(field_pkg);
|
||||
if (!data_field_element_name.has_value())
|
||||
return ParseResult::Failure;
|
||||
auto data_field_element = context.root_namespace->find_object(context.scope.span(), data_field_element_name.value());
|
||||
auto data_field_element = context.root_namespace->find_object(context.scope, data_field_element_name.value());
|
||||
if (!data_field_element || data_field_element->type != AML::Node::Type::FieldElement)
|
||||
{
|
||||
AML_ERROR("IndexField DataName does not name a valid FieldElement");
|
||||
@@ -197,7 +197,7 @@ namespace Kernel::ACPI
|
||||
|
||||
NameString element_name;
|
||||
MUST(element_name.path.push_back(element->name));
|
||||
if (!context.root_namespace->add_named_object(context.scope.span(), element_name, element))
|
||||
if (!context.root_namespace->add_named_object(context, element_name, element))
|
||||
return ParseResult::Failure;
|
||||
|
||||
#if AML_DEBUG_LEVEL >= 2
|
||||
|
||||
@@ -19,7 +19,7 @@ namespace Kernel::ACPI
|
||||
return ParseResult::Failure;
|
||||
|
||||
auto name = MUST(BAN::RefPtr<Name>::create(name_string.value().path.back(), object.node()));
|
||||
if (!context.root_namespace->add_named_object(context.scope.span(), name_string.value(), name))
|
||||
if (!context.root_namespace->add_named_object(context, name_string.value(), name))
|
||||
return ParseResult::Failure;
|
||||
|
||||
#if AML_DEBUG_LEVEL >= 2
|
||||
|
||||
@@ -5,69 +5,117 @@
|
||||
namespace Kernel::ACPI
|
||||
{
|
||||
|
||||
BAN::Optional<BAN::Vector<AML::NameSeg>> AML::Namespace::resolve_path(BAN::Span<const AML::NameSeg> parsing_scope, const AML::NameString& relative_path)
|
||||
BAN::Optional<AML::NameString> AML::Namespace::resolve_path(const AML::NameString& relative_base, const AML::NameString& relative_path)
|
||||
{
|
||||
BAN::Vector<NameSeg> canonical_path;
|
||||
// Base must be non-empty absolute path
|
||||
ASSERT(relative_base.prefix == "\\"sv || relative_base.path.empty());
|
||||
|
||||
if (!relative_path.prefix.empty())
|
||||
// Do absolute path lookup
|
||||
if (!relative_path.prefix.empty() || relative_path.path.size() != 1)
|
||||
{
|
||||
if (relative_path.prefix[0] == '\\')
|
||||
AML::NameString absolute_path;
|
||||
MUST(absolute_path.prefix.push_back('\\'));
|
||||
|
||||
// Resolve root and parent references
|
||||
if (relative_path.prefix == "\\"sv)
|
||||
;
|
||||
else
|
||||
{
|
||||
if (parsing_scope.size() < relative_path.prefix.size())
|
||||
if (relative_path.prefix.size() > relative_base.path.size())
|
||||
{
|
||||
AML_ERROR("Trying to resolve parent of root object");
|
||||
return {};
|
||||
}
|
||||
for (size_t i = 0; i < parsing_scope.size() - relative_path.prefix.size(); i++)
|
||||
MUST(canonical_path.push_back(parsing_scope[i]));
|
||||
for (size_t i = 0; i < relative_base.path.size() - relative_path.prefix.size(); i++)
|
||||
MUST(absolute_path.path.push_back(relative_base.path[i]));
|
||||
}
|
||||
|
||||
// Append relative path
|
||||
for (const auto& seg : relative_path.path)
|
||||
MUST(absolute_path.path.push_back(seg));
|
||||
|
||||
// Validate path
|
||||
BAN::RefPtr<AML::NamedObject> current_node = this;
|
||||
for (const auto& seg : absolute_path.path)
|
||||
{
|
||||
if (!current_node->is_scope())
|
||||
return {};
|
||||
|
||||
auto* current_scope = static_cast<AML::Scope*>(current_node.ptr());
|
||||
auto it = current_scope->objects.find(seg);
|
||||
if (it == current_scope->objects.end())
|
||||
return {};
|
||||
|
||||
current_node = it->value;
|
||||
}
|
||||
return absolute_path;
|
||||
}
|
||||
|
||||
|
||||
// Resolve with namespace search rules (ACPI Spec 6.4 - Section 5.3)
|
||||
|
||||
AML::NameString last_match_path;
|
||||
AML::NameSeg target_seg = relative_path.path.back();
|
||||
|
||||
BAN::RefPtr<AML::Scope> current_scope = this;
|
||||
AML::NameString current_path;
|
||||
|
||||
// Check root namespace
|
||||
{
|
||||
// If scope contains object with the same name as the segment, update last match
|
||||
if (current_scope->objects.contains(target_seg))
|
||||
{
|
||||
last_match_path = current_path;
|
||||
MUST(last_match_path.path.push_back(target_seg));
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
// Check base base path
|
||||
for (const auto& seg : relative_base.path)
|
||||
{
|
||||
for (auto seg : parsing_scope)
|
||||
MUST(canonical_path.push_back(seg));
|
||||
auto next_node = current_scope->objects[seg];
|
||||
ASSERT(next_node && next_node->is_scope());
|
||||
|
||||
current_scope = static_cast<AML::Scope*>(next_node.ptr());
|
||||
MUST(current_path.path.push_back(seg));
|
||||
|
||||
// If scope contains object with the same name as the segment, update last match
|
||||
if (current_scope->objects.contains(target_seg))
|
||||
{
|
||||
last_match_path = current_path;
|
||||
MUST(last_match_path.path.push_back(target_seg));
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto& seg : relative_path.path)
|
||||
MUST(canonical_path.push_back(seg));
|
||||
if (!last_match_path.path.empty())
|
||||
{
|
||||
MUST(last_match_path.prefix.push_back('\\'));
|
||||
return last_match_path;
|
||||
}
|
||||
|
||||
return canonical_path;
|
||||
return {};
|
||||
}
|
||||
|
||||
BAN::RefPtr<AML::NamedObject> AML::Namespace::find_object(BAN::Span<const AML::NameSeg> parsing_scope, const AML::NameString& relative_path)
|
||||
BAN::RefPtr<AML::NamedObject> AML::Namespace::find_object(const AML::NameString& relative_base, const AML::NameString& relative_path)
|
||||
{
|
||||
auto canonical_path = resolve_path(parsing_scope, relative_path);
|
||||
auto canonical_path = resolve_path(relative_base, relative_path);
|
||||
if (!canonical_path.has_value())
|
||||
return nullptr;
|
||||
if (canonical_path->empty())
|
||||
if (canonical_path->path.empty())
|
||||
return this;
|
||||
|
||||
BAN::RefPtr<NamedObject> parent_object = this;
|
||||
|
||||
for (const auto& seg : canonical_path.value())
|
||||
BAN::RefPtr<NamedObject> node = this;
|
||||
for (const auto& seg : canonical_path->path)
|
||||
{
|
||||
if (!parent_object->is_scope())
|
||||
{
|
||||
AML_ERROR("Parent object is not a scope");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto* parent_scope = static_cast<Scope*>(parent_object.ptr());
|
||||
|
||||
auto it = parent_scope->objects.find(seg);
|
||||
if (it == parent_scope->objects.end())
|
||||
return nullptr;
|
||||
|
||||
parent_object = it->value;
|
||||
ASSERT(parent_object);
|
||||
// Resolve path validates that all nodes are scopes
|
||||
ASSERT(node->is_scope());
|
||||
node = static_cast<Scope*>(node.ptr())->objects[seg];
|
||||
}
|
||||
|
||||
return parent_object;
|
||||
return node;
|
||||
}
|
||||
|
||||
bool AML::Namespace::add_named_object(BAN::Span<const NameSeg> parsing_scope, const AML::NameString& object_path, BAN::RefPtr<NamedObject> object)
|
||||
bool AML::Namespace::add_named_object(ParseContext& parse_context, const AML::NameString& object_path, BAN::RefPtr<NamedObject> object)
|
||||
{
|
||||
ASSERT(!object_path.path.empty());
|
||||
ASSERT(object_path.path.back() == object->name);
|
||||
@@ -75,7 +123,7 @@ namespace Kernel::ACPI
|
||||
auto parent_path = object_path;
|
||||
parent_path.path.pop_back();
|
||||
|
||||
auto parent_object = find_object(parsing_scope, parent_path);
|
||||
auto parent_object = find_object(parse_context.scope, parent_path);
|
||||
if (!parent_object)
|
||||
{
|
||||
AML_ERROR("Parent object not found");
|
||||
@@ -96,17 +144,88 @@ namespace Kernel::ACPI
|
||||
}
|
||||
|
||||
MUST(parent_scope->objects.insert(object->name, object));
|
||||
|
||||
auto canonical_scope = resolve_path(parse_context.scope, object_path);
|
||||
ASSERT(canonical_scope.has_value());
|
||||
if (object->is_scope())
|
||||
{
|
||||
auto* scope = static_cast<Scope*>(object.ptr());
|
||||
scope->scope = canonical_scope.value();
|
||||
}
|
||||
MUST(parse_context.created_objects.push_back(BAN::move(canonical_scope.release_value())));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AML::Namespace::remove_named_object(const AML::NameString& absolute_path)
|
||||
{
|
||||
auto canonical_path = resolve_path({}, absolute_path);
|
||||
if (!canonical_path.has_value())
|
||||
{
|
||||
AML_ERROR("Failed to resolve path");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (canonical_path->path.empty())
|
||||
{
|
||||
AML_ERROR("Trying to remove root object");
|
||||
return false;
|
||||
}
|
||||
|
||||
BAN::RefPtr<NamedObject> parent_object = this;
|
||||
|
||||
for (size_t i = 0; i < canonical_path->path.size() - 1; i++)
|
||||
{
|
||||
if (!parent_object->is_scope())
|
||||
{
|
||||
AML_ERROR("Parent object is not a scope");
|
||||
return false;
|
||||
}
|
||||
|
||||
auto* parent_scope = static_cast<Scope*>(parent_object.ptr());
|
||||
|
||||
auto it = parent_scope->objects.find(canonical_path->path[i]);
|
||||
if (it == parent_scope->objects.end())
|
||||
{
|
||||
AML_ERROR("Object not found");
|
||||
return false;
|
||||
}
|
||||
|
||||
parent_object = it->value;
|
||||
ASSERT(parent_object);
|
||||
}
|
||||
|
||||
if (!parent_object->is_scope())
|
||||
{
|
||||
AML_ERROR("Parent object is not a scope");
|
||||
return false;
|
||||
}
|
||||
|
||||
auto* parent_scope = static_cast<Scope*>(parent_object.ptr());
|
||||
parent_scope->objects.remove(canonical_path->path.back());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
BAN::RefPtr<AML::Namespace> AML::Namespace::parse(BAN::ConstByteSpan aml_data)
|
||||
{
|
||||
auto result = MUST(BAN::RefPtr<Namespace>::create());
|
||||
auto result = MUST(BAN::RefPtr<Namespace>::create(NameSeg("\\"sv)));
|
||||
|
||||
AML::ParseContext context;
|
||||
context.scope = AML::NameString("\\"sv);
|
||||
context.aml_data = aml_data;
|
||||
context.root_namespace = result.ptr();
|
||||
|
||||
// Add predefined namespaces
|
||||
#define ADD_PREDEFIED_NAMESPACE(NAME) \
|
||||
ASSERT(result->add_named_object(context, AML::NameString("\\" NAME), MUST(BAN::RefPtr<AML::Namespace>::create(NameSeg(NAME)))));
|
||||
ADD_PREDEFIED_NAMESPACE("_GPE"sv);
|
||||
ADD_PREDEFIED_NAMESPACE("_PR"sv);
|
||||
ADD_PREDEFIED_NAMESPACE("_SB"sv);
|
||||
ADD_PREDEFIED_NAMESPACE("_SI"sv);
|
||||
ADD_PREDEFIED_NAMESPACE("_TZ"sv);
|
||||
#undef ADD_PREDEFIED_NAMESPACE
|
||||
|
||||
while (context.aml_data.size() > 0)
|
||||
{
|
||||
auto result = AML::parse_object(context);
|
||||
|
||||
@@ -86,10 +86,10 @@ namespace Kernel::ACPI
|
||||
auto name_string = AML::NameString::parse(context.aml_data);
|
||||
if (!name_string.has_value())
|
||||
return ParseResult::Failure;
|
||||
auto aml_object = context.root_namespace->find_object(context.scope.span(), name_string.value());
|
||||
auto aml_object = context.root_namespace->find_object(context.scope, name_string.value());
|
||||
if (!aml_object)
|
||||
{
|
||||
AML_TODO("NameString not found in namespace");
|
||||
AML_ERROR("NameString {} not found in namespace", name_string.value());
|
||||
return ParseResult::Failure;
|
||||
}
|
||||
return ParseResult(aml_object);
|
||||
|
||||
@@ -20,33 +20,30 @@ namespace Kernel::ACPI
|
||||
if (!name_string.has_value())
|
||||
return ParseResult::Failure;
|
||||
|
||||
BAN::RefPtr<Scope> scope;
|
||||
if (auto named_object = context.root_namespace->find_object(context.scope.span(), name_string.value()))
|
||||
auto named_object = context.root_namespace->find_object(context.scope, name_string.value());
|
||||
if (!named_object)
|
||||
{
|
||||
if (!named_object->is_scope())
|
||||
{
|
||||
AML_ERROR("Scope name already exists and is not a scope");
|
||||
return ParseResult::Failure;
|
||||
}
|
||||
scope = static_cast<Scope*>(named_object.ptr());
|
||||
AML_ERROR("Scope name {} not found in namespace", name_string.value());
|
||||
return ParseResult::Failure;
|
||||
}
|
||||
else
|
||||
if (!named_object->is_scope())
|
||||
{
|
||||
scope = MUST(BAN::RefPtr<Scope>::create(name_string->path.back()));
|
||||
if (!context.root_namespace->add_named_object(context.scope.span(), name_string.value(), scope))
|
||||
return ParseResult::Failure;
|
||||
AML_ERROR("Scope name {} does not name a namespace", name_string.value());
|
||||
return ParseResult::Failure;
|
||||
}
|
||||
|
||||
auto* scope = static_cast<Scope*>(named_object.ptr());
|
||||
return scope->enter_context_and_parse_term_list(context, name_string.value(), scope_pkg.value());
|
||||
}
|
||||
|
||||
AML::ParseResult AML::Scope::enter_context_and_parse_term_list(ParseContext& outer_context, const AML::NameString& name_string, BAN::ConstByteSpan aml_data)
|
||||
{
|
||||
auto scope = outer_context.root_namespace->resolve_path(outer_context.scope.span(), name_string);
|
||||
auto scope = outer_context.root_namespace->resolve_path(outer_context.scope, name_string);
|
||||
if (!scope.has_value())
|
||||
return ParseResult::Failure;
|
||||
|
||||
ParseContext scope_context = outer_context;
|
||||
ParseContext scope_context;
|
||||
scope_context.root_namespace = outer_context.root_namespace;
|
||||
scope_context.scope = scope.release_value();
|
||||
scope_context.aml_data = aml_data;
|
||||
while (scope_context.aml_data.size() > 0)
|
||||
@@ -56,6 +53,9 @@ namespace Kernel::ACPI
|
||||
return ParseResult::Failure;
|
||||
}
|
||||
|
||||
for (auto& name : scope_context.created_objects)
|
||||
MUST(outer_context.created_objects.push_back(BAN::move(name)));
|
||||
|
||||
return ParseResult::Success;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user