From 23fa39121cf17f60dba232b38592ea70fcf6c8cd Mon Sep 17 00:00:00 2001 From: Bananymous Date: Tue, 9 Apr 2024 18:37:51 +0300 Subject: [PATCH] Kernel: Start working on AML method evaluations Also fix namespace lookup and scope creations. --- kernel/include/kernel/ACPI/AML/Device.h | 60 +++++- kernel/include/kernel/ACPI/AML/Method.h | 59 +++++- kernel/include/kernel/ACPI/AML/Mutex.h | 2 +- kernel/include/kernel/ACPI/AML/Names.h | 59 ++++++ kernel/include/kernel/ACPI/AML/Namespace.h | 11 +- kernel/include/kernel/ACPI/AML/Node.h | 2 +- kernel/include/kernel/ACPI/AML/ParseContext.h | 13 +- kernel/include/kernel/ACPI/AML/Processor.h | 4 +- kernel/include/kernel/ACPI/AML/Region.h | 2 +- kernel/include/kernel/ACPI/AML/Scope.h | 5 +- kernel/kernel/ACPI/AML/Field.cpp | 12 +- kernel/kernel/ACPI/AML/NamedObject.cpp | 2 +- kernel/kernel/ACPI/AML/Namespace.cpp | 193 ++++++++++++++---- kernel/kernel/ACPI/AML/Node.cpp | 4 +- kernel/kernel/ACPI/AML/Scope.cpp | 28 +-- 15 files changed, 371 insertions(+), 85 deletions(-) diff --git a/kernel/include/kernel/ACPI/AML/Device.h b/kernel/include/kernel/ACPI/AML/Device.h index dadd0824..d036c15f 100644 --- a/kernel/include/kernel/ACPI/AML/Device.h +++ b/kernel/include/kernel/ACPI/AML/Device.h @@ -1,5 +1,6 @@ #pragma once +#include #include #include #include @@ -9,7 +10,9 @@ namespace Kernel::ACPI::AML struct Device : public AML::Scope { - Device(NameSeg name) : Scope(name, Node::Type::Device) {} + Device(NameSeg name) + : Scope(Node::Type::Device, name) + {} static ParseResult parse(ParseContext& context) { @@ -27,12 +30,65 @@ namespace Kernel::ACPI::AML return ParseResult::Failure; auto device = MUST(BAN::RefPtr::create(name_string->path.back())); - if (!context.root_namespace->add_named_object(context.scope.span(), name_string.value(), device)) + if (!context.root_namespace->add_named_object(context, name_string.value(), device)) return ParseResult::Failure; return device->enter_context_and_parse_term_list(context, name_string.value(), device_pkg.value()); } + void initialize(BAN::RefPtr root_namespace) + { + bool run_ini = true; + bool init_children = true; + + auto _sta = root_namespace->find_object(scope, NameString("_STA"sv)); + if (_sta && _sta->type == Node::Type::Method) + { + auto* method = static_cast(_sta.ptr()); + auto result = method->evaluate(root_namespace); + if (!result.has_value()) + { + AML_ERROR("Failed to evaluate {}._STA", scope); + return; + } + if (!result.value()) + { + AML_ERROR("Failed to evaluate {}._STA, return value is null", scope); + return; + } + auto result_val = result.value()->as_integer(); + if (!result_val.has_value()) + { + AML_ERROR("Failed to evaluate {}._STA, return value could not be resolved to integer", scope); + return; + } + run_ini = (result_val.value() & 0x01); + init_children = run_ini || (result_val.value() & 0x02); + } + + if (run_ini) + { + auto _ini = root_namespace->find_object(scope, NameString("_INI"sv)); + if (_ini && _ini->type == Node::Type::Method) + { + auto* method = static_cast(_ini.ptr()); + method->evaluate(root_namespace); + } + } + + if (init_children) + { + for (auto& [_, child] : objects) + { + if (child->type == Node::Type::Device) + { + auto* device = static_cast(child.ptr()); + device->initialize(root_namespace); + } + } + } + } + virtual void debug_print(int indent) const override { AML_DEBUG_PRINT_INDENT(indent); diff --git a/kernel/include/kernel/ACPI/AML/Method.h b/kernel/include/kernel/ACPI/AML/Method.h index 8c3154ba..163b6683 100644 --- a/kernel/include/kernel/ACPI/AML/Method.h +++ b/kernel/include/kernel/ACPI/AML/Method.h @@ -1,14 +1,15 @@ #pragma once #include -#include +#include #include #include +#include namespace Kernel::ACPI::AML { - struct Method : public AML::NamedObject + struct Method : public AML::Scope { uint8_t arg_count; bool serialized; @@ -16,12 +17,11 @@ namespace Kernel::ACPI::AML BAN::ConstByteSpan term_list; - Method(AML::NameSeg name, uint8_t arg_count, bool serialized, uint8_t sync_level, BAN::ConstByteSpan term_list) - : AML::NamedObject(Node::Type::Method, name) + Method(AML::NameSeg name, uint8_t arg_count, bool serialized, uint8_t sync_level) + : AML::Scope(Node::Type::Method, name) , arg_count(arg_count) , serialized(serialized) , sync_level(sync_level) - , term_list(term_list) {} static ParseResult parse(AML::ParseContext& context) @@ -47,13 +47,17 @@ namespace Kernel::ACPI::AML name_string.value().path.back(), method_flags & 0x07, (method_flags >> 3) & 0x01, - method_flags >> 4, - method_pkg.value() + method_flags >> 4 )); - - if (!context.root_namespace->add_named_object(context.scope.span(), name_string.value(), method)) + if (!context.root_namespace->add_named_object(context, name_string.value(), method)) return ParseResult::Failure; + auto method_scope = context.root_namespace->resolve_path(context.scope, name_string.value()); + if (!method_scope.has_value()) + return ParseResult::Failure; + method->term_list = method_pkg.value(); + method->scope = method_scope.release_value(); + #if AML_DEBUG_LEVEL >= 2 method->debug_print(0); AML_DEBUG_PRINTLN(""); @@ -62,6 +66,43 @@ namespace Kernel::ACPI::AML return ParseResult::Success; } + BAN::Optional> evaluate(BAN::RefPtr root_namespace) + { + ParseContext context; + context.root_namespace = root_namespace.ptr(); + context.aml_data = term_list; + context.scope = scope; + + AML_DEBUG_PRINTLN("Evaluating method {}", scope); + + BAN::Optional> return_value; + + ASSERT(arg_count == 0); + while (context.aml_data.size() > 0) + { + if (static_cast(context.aml_data[0]) == AML::Byte::ReturnOp) + { + context.aml_data = context.aml_data.slice(1); + auto result = AML::parse_object(context); + if (result.success()) + return_value = result.node(); + break; + } + + auto object_result = AML::parse_object(context); + if (!object_result.success()) + break; + } + + while (!context.created_objects.empty()) + { + root_namespace->remove_named_object(context.created_objects.back()); + context.created_objects.pop_back(); + } + + return return_value; + } + virtual void debug_print(int indent) const override { AML_DEBUG_PRINT_INDENT(indent); diff --git a/kernel/include/kernel/ACPI/AML/Mutex.h b/kernel/include/kernel/ACPI/AML/Mutex.h index 7d90cf3b..a29fcf8a 100644 --- a/kernel/include/kernel/ACPI/AML/Mutex.h +++ b/kernel/include/kernel/ACPI/AML/Mutex.h @@ -39,7 +39,7 @@ namespace Kernel::ACPI::AML } auto mutex = MUST(BAN::RefPtr::create(name->path.back(), sync_level)); - if (!context.root_namespace->add_named_object(context.scope.span(), name.value(), mutex)) + if (!context.root_namespace->add_named_object(context, name.value(), mutex)) return ParseResult::Failure; #if AML_DEBUG_LEVEL >= 2 diff --git a/kernel/include/kernel/ACPI/AML/Names.h b/kernel/include/kernel/ACPI/AML/Names.h index 9df82345..64719e78 100644 --- a/kernel/include/kernel/ACPI/AML/Names.h +++ b/kernel/include/kernel/ACPI/AML/Names.h @@ -70,6 +70,42 @@ namespace Kernel::ACPI::AML BAN::String prefix; BAN::Vector path; + NameString() = default; + NameString(BAN::StringView str) + { + if (!str.empty() && str.front() == '\\') + { + MUST(prefix.push_back('\\')); + str = str.substring(1); + } + else + { + while (str.size() > 0 && str.front() == '^') + { + MUST(prefix.push_back('^')); + str = str.substring(1); + } + } + + while (!str.empty()) + { + ASSERT(str[0] != '.'); + size_t len = 1; + while (len < str.size() && str[len] != '.') + len++; + ASSERT(len <= 4); + + MUST(path.push_back(NameSeg(str.substring(0, len)))); + str = str.substring(len); + + if (!str.empty()) + { + ASSERT(str[0] == '.'); + str = str.substring(1); + } + } + } + static BAN::Optional parse(BAN::ConstByteSpan& aml_data) { if (aml_data.size() == 0) @@ -154,4 +190,27 @@ namespace BAN } }; + template + void Formatter::print_argument(F putc, const Kernel::ACPI::AML::NameSeg& name_seg, const ValueFormat&) + { + size_t len = 4; + while (len > 0 && name_seg.chars[len - 1] == '_') + len--; + for (size_t i = 0; i < len; i++) + putc(name_seg.chars[i]); + } + + template + void Formatter::print_argument(F putc, const Kernel::ACPI::AML::NameString& name_string, const ValueFormat&) + { + print_argument(putc, name_string.prefix, {}); + if (!name_string.path.empty()) + print_argument(putc, name_string.path.front(), {}); + for (size_t i = 1; i < name_string.path.size(); i++) + { + putc('.'); + print_argument(putc, name_string.path[i], {}); + } + } + } diff --git a/kernel/include/kernel/ACPI/AML/Namespace.h b/kernel/include/kernel/ACPI/AML/Namespace.h index 758a2caf..592644f7 100644 --- a/kernel/include/kernel/ACPI/AML/Namespace.h +++ b/kernel/include/kernel/ACPI/AML/Namespace.h @@ -7,17 +7,20 @@ namespace Kernel::ACPI::AML struct Namespace : public AML::Scope { - Namespace() : AML::Scope(NameSeg("\\"sv)) {} + Namespace(NameSeg name) : AML::Scope(Node::Type::Namespace, name) {} static BAN::RefPtr parse(BAN::ConstByteSpan aml); - BAN::Optional> resolve_path(BAN::Span parsing_scope, const AML::NameString& relative_path); + BAN::Optional resolve_path(const AML::NameString& relative_base, const AML::NameString& relative_path); // Find an object in the namespace. Returns nullptr if the object is not found. - BAN::RefPtr find_object(BAN::Span parsing_scope, const AML::NameString& relative_path); + BAN::RefPtr find_object(const AML::NameString& relative_base, const AML::NameString& relative_path); // Add an object to the namespace. Returns false if the parent object could not be added. - bool add_named_object(BAN::Span parsing_scope, const AML::NameString& object_path, BAN::RefPtr object); + bool add_named_object(ParseContext&, const AML::NameString& object_path, BAN::RefPtr object); + + // Remove an object from the namespace. Returns false if the object could not be removed. + bool remove_named_object(const AML::NameString& absolute_path); }; } diff --git a/kernel/include/kernel/ACPI/AML/Node.h b/kernel/include/kernel/ACPI/AML/Node.h index 1a6200aa..e04a3bc0 100644 --- a/kernel/include/kernel/ACPI/AML/Node.h +++ b/kernel/include/kernel/ACPI/AML/Node.h @@ -20,10 +20,10 @@ namespace Kernel::ACPI::AML Method, Mutex, Name, + Namespace, OpRegion, Package, Processor, - Scope, String, }; const Type type; diff --git a/kernel/include/kernel/ACPI/AML/ParseContext.h b/kernel/include/kernel/ACPI/AML/ParseContext.h index 8cc0f2e9..38d45492 100644 --- a/kernel/include/kernel/ACPI/AML/ParseContext.h +++ b/kernel/include/kernel/ACPI/AML/ParseContext.h @@ -1,7 +1,7 @@ #pragma once #include -#include +#include #include #include @@ -10,9 +10,14 @@ namespace Kernel::ACPI::AML struct ParseContext { - BAN::ConstByteSpan aml_data; - BAN::Vector scope; - struct Namespace* root_namespace; + BAN::ConstByteSpan aml_data; + AML::NameString scope; + AML::Namespace* root_namespace; + + // Used for cleaning up on method exit + // NOTE: This uses linked list instead of vector because + // we don't really need large contiguous memory + BAN::LinkedList created_objects; }; } diff --git a/kernel/include/kernel/ACPI/AML/Processor.h b/kernel/include/kernel/ACPI/AML/Processor.h index 2e91aa42..55e294b9 100644 --- a/kernel/include/kernel/ACPI/AML/Processor.h +++ b/kernel/include/kernel/ACPI/AML/Processor.h @@ -16,7 +16,7 @@ namespace Kernel::ACPI::AML uint8_t pblk_len; Processor(NameSeg name, uint8_t id, uint32_t pblk_addr, uint8_t pblk_len) - : Scope(name, Node::Type::Processor) + : Scope(Node::Type::Processor, name) , id(id) , pblk_addr(pblk_addr) , pblk_len(pblk_len) @@ -53,7 +53,7 @@ namespace Kernel::ACPI::AML processor_pkg = processor_pkg->slice(1); auto processor = MUST(BAN::RefPtr::create(name->path.back(), id, pblk_addr, pblk_len)); - if (!context.root_namespace->add_named_object(context.scope.span(), name.value(), processor)) + if (!context.root_namespace->add_named_object(context, name.value(), processor)) return ParseResult::Failure; return processor->enter_context_and_parse_term_list(context, name.value(), processor_pkg.value()); diff --git a/kernel/include/kernel/ACPI/AML/Region.h b/kernel/include/kernel/ACPI/AML/Region.h index bbe03186..f589a26e 100644 --- a/kernel/include/kernel/ACPI/AML/Region.h +++ b/kernel/include/kernel/ACPI/AML/Region.h @@ -74,7 +74,7 @@ namespace Kernel::ACPI::AML length.value() )); - if (!context.root_namespace->add_named_object(context.scope.span(), name.value(), op_region)) + if (!context.root_namespace->add_named_object(context, name.value(), op_region)) return ParseResult::Failure; #if AML_DEBUG_LEVEL >= 2 diff --git a/kernel/include/kernel/ACPI/AML/Scope.h b/kernel/include/kernel/ACPI/AML/Scope.h index aeeca7d9..b1a5498b 100644 --- a/kernel/include/kernel/ACPI/AML/Scope.h +++ b/kernel/include/kernel/ACPI/AML/Scope.h @@ -10,8 +10,11 @@ namespace Kernel::ACPI::AML struct Scope : public AML::NamedObject { BAN::HashMap> objects; + AML::NameString scope; - Scope(NameSeg name, Node::Type type = Node::Type::Scope) : NamedObject(type, name) {} + Scope(Node::Type type, NameSeg name) + : NamedObject(type, name) + {} virtual bool is_scope() const override { return true; } diff --git a/kernel/kernel/ACPI/AML/Field.cpp b/kernel/kernel/ACPI/AML/Field.cpp index d525ecaf..58aef111 100644 --- a/kernel/kernel/ACPI/AML/Field.cpp +++ b/kernel/kernel/ACPI/AML/Field.cpp @@ -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 diff --git a/kernel/kernel/ACPI/AML/NamedObject.cpp b/kernel/kernel/ACPI/AML/NamedObject.cpp index 7779909c..8708c6d2 100644 --- a/kernel/kernel/ACPI/AML/NamedObject.cpp +++ b/kernel/kernel/ACPI/AML/NamedObject.cpp @@ -19,7 +19,7 @@ namespace Kernel::ACPI return ParseResult::Failure; auto name = MUST(BAN::RefPtr::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 diff --git a/kernel/kernel/ACPI/AML/Namespace.cpp b/kernel/kernel/ACPI/AML/Namespace.cpp index 93d48dba..a8fc8700 100644 --- a/kernel/kernel/ACPI/AML/Namespace.cpp +++ b/kernel/kernel/ACPI/AML/Namespace.cpp @@ -5,69 +5,117 @@ namespace Kernel::ACPI { - BAN::Optional> AML::Namespace::resolve_path(BAN::Span parsing_scope, const AML::NameString& relative_path) + BAN::Optional AML::Namespace::resolve_path(const AML::NameString& relative_base, const AML::NameString& relative_path) { - BAN::Vector 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 current_node = this; + for (const auto& seg : absolute_path.path) + { + if (!current_node->is_scope()) + return {}; + + auto* current_scope = static_cast(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 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(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::Namespace::find_object(BAN::Span parsing_scope, const AML::NameString& relative_path) + BAN::RefPtr 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 parent_object = this; - - for (const auto& seg : canonical_path.value()) + BAN::RefPtr 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(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(node.ptr())->objects[seg]; } - return parent_object; + return node; } - bool AML::Namespace::add_named_object(BAN::Span parsing_scope, const AML::NameString& object_path, BAN::RefPtr object) + bool AML::Namespace::add_named_object(ParseContext& parse_context, const AML::NameString& object_path, BAN::RefPtr 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(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 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(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(parent_object.ptr()); + parent_scope->objects.remove(canonical_path->path.back()); + return true; } BAN::RefPtr AML::Namespace::parse(BAN::ConstByteSpan aml_data) { - auto result = MUST(BAN::RefPtr::create()); + auto result = MUST(BAN::RefPtr::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::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); diff --git a/kernel/kernel/ACPI/AML/Node.cpp b/kernel/kernel/ACPI/AML/Node.cpp index ecbade89..b0f7b23a 100644 --- a/kernel/kernel/ACPI/AML/Node.cpp +++ b/kernel/kernel/ACPI/AML/Node.cpp @@ -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); diff --git a/kernel/kernel/ACPI/AML/Scope.cpp b/kernel/kernel/ACPI/AML/Scope.cpp index db8ff441..41997cb9 100644 --- a/kernel/kernel/ACPI/AML/Scope.cpp +++ b/kernel/kernel/ACPI/AML/Scope.cpp @@ -20,33 +20,30 @@ namespace Kernel::ACPI if (!name_string.has_value()) return ParseResult::Failure; - BAN::RefPtr 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(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::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(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; }