diff --git a/kernel/CMakeLists.txt b/kernel/CMakeLists.txt index f0c14178..9db24017 100644 --- a/kernel/CMakeLists.txt +++ b/kernel/CMakeLists.txt @@ -16,6 +16,7 @@ set(KERNEL_SOURCES kernel/ACPI/AML/NamedObject.cpp kernel/ACPI/AML/Namespace.cpp kernel/ACPI/AML/Node.cpp + kernel/ACPI/AML/Package.cpp kernel/ACPI/AML/Scope.cpp kernel/APIC.cpp kernel/BootInfo.cpp diff --git a/kernel/include/kernel/ACPI/AML/Index.h b/kernel/include/kernel/ACPI/AML/Index.h index 3c785004..d350f3e3 100644 --- a/kernel/include/kernel/ACPI/AML/Index.h +++ b/kernel/include/kernel/ACPI/AML/Index.h @@ -2,6 +2,7 @@ #include #include +#include #include #include @@ -52,8 +53,17 @@ namespace Kernel::ACPI::AML break; } case AML::Node::Type::Package: - AML_TODO("IndexOp source Package"); - return ParseResult::Failure; + { + auto package = static_cast(source.ptr()); + if (index.value() >= package->elements.size()) + { + AML_ERROR("IndexOp index is out of package bounds"); + return ParseResult::Failure; + } + auto package_element = package->elements[index.value()]; + result = MUST(BAN::RefPtr::create(package_element)); + break; + } case AML::Node::Type::String: AML_TODO("IndexOp source String"); return ParseResult::Failure; diff --git a/kernel/include/kernel/ACPI/AML/Node.h b/kernel/include/kernel/ACPI/AML/Node.h index 6377f89d..10c0876b 100644 --- a/kernel/include/kernel/ACPI/AML/Node.h +++ b/kernel/include/kernel/ACPI/AML/Node.h @@ -28,6 +28,7 @@ namespace Kernel::ACPI::AML Namespace, OpRegion, Package, + PackageElement, PowerResource, Processor, Reference, diff --git a/kernel/include/kernel/ACPI/AML/Package.h b/kernel/include/kernel/ACPI/AML/Package.h index 0001186d..13923cc6 100644 --- a/kernel/include/kernel/ACPI/AML/Package.h +++ b/kernel/include/kernel/ACPI/AML/Package.h @@ -8,109 +8,124 @@ namespace Kernel::ACPI::AML { + struct PackageElement; + struct Package : public AML::Node { - struct UnresolvedReference - { - AML::NameString name; - size_t index; - }; - BAN::Vector unresolved_references; - AML::NameString scope; // Used for resolving references + BAN::Vector> elements; + AML::NameString scope; - BAN::Vector> elements; - - Package(BAN::Vector>&& elements, BAN::Vector&& unresolved_references, AML::NameString scope) + Package(AML::NameString scope) : Node(Node::Type::Package) , elements(BAN::move(elements)) - , unresolved_references(BAN::move(unresolved_references)) , scope(scope) {} BAN::RefPtr evaluate() override { - // resolve references - for (auto& reference : unresolved_references) - { - auto object = Namespace::root_namespace()->find_object(scope, reference.name, Namespace::FindMode::Normal); - if (!object) - { - AML_ERROR("Failed to resolve reference {} in package", reference.name); - return {}; - } - ASSERT(!elements[reference.index]); - elements[reference.index] = object; - } - unresolved_references.clear(); - return this; } - static ParseResult parse(AML::ParseContext& context) + static ParseResult parse(AML::ParseContext& context); + virtual void debug_print(int indent) const override; + }; + + struct PackageElement : public AML::Node + { + BAN::RefPtr parent; + BAN::RefPtr element; + AML::NameString unresolved_name; + bool resolved = false; + bool initialized = false; + + PackageElement(BAN::RefPtr parent, BAN::RefPtr element) + : Node(Node::Type::PackageElement) + , parent(parent) + , element(element) { - ASSERT(context.aml_data.size() >= 1); - ASSERT(static_cast(context.aml_data[0]) == Byte::PackageOp); - context.aml_data = context.aml_data.slice(1); + ASSERT(element); + resolved = true; + initialized = true; + } - auto package_pkg = AML::parse_pkg(context.aml_data); - if (!package_pkg.has_value()) - return ParseResult::Failure; + PackageElement(BAN::RefPtr parent, AML::NameString unresolved_name) + : Node(Node::Type::PackageElement) + , parent(parent) + , unresolved_name(unresolved_name) + { + resolved = false; + initialized = true; + } - auto package_context = context; - package_context.aml_data = package_pkg.value(); + PackageElement(BAN::RefPtr parent) + : Node(Node::Type::PackageElement) + , parent(parent) + , unresolved_name(unresolved_name) + { + resolved = false; + initialized = false; + } - if (package_pkg->size() < 1) - return ParseResult::Failure; - uint8_t num_elements = package_context.aml_data[0]; - package_context.aml_data = package_context.aml_data.slice(1); - - BAN::Vector> elements; - BAN::Vector unresolved_references; - while (elements.size() < num_elements && package_context.aml_data.size() > 0) + BAN::RefPtr evaluate() override + { + if (!initialized) { - BAN::RefPtr element; - - // Store name strings as references - if (package_context.aml_data[0] != 0x00 && AML::NameString::can_parse(package_context.aml_data)) - { - auto name = AML::NameString::parse(package_context.aml_data); - if (!name.has_value()) - return ParseResult::Failure; - MUST(unresolved_references.push_back(UnresolvedReference { .name = name.value(), .index = elements.size() })); - } - else - { - auto element_result = AML::parse_object(package_context); - if (!element_result.success()) - return ParseResult::Failure; - element = element_result.node(); - } - - MUST(elements.push_back(element)); + AML_ERROR("Trying to evaluate uninitialized PackageElement"); + return {}; } - while (elements.size() < num_elements) - MUST(elements.push_back(BAN::RefPtr())); + if (!resolved) + { + auto object = Namespace::root_namespace()->find_object(parent->scope, unresolved_name, Namespace::FindMode::Normal); + if (!object) + { + AML_ERROR("Failed to resolve reference {} in package {}", unresolved_name, parent->scope); + return {}; + } + element = object; + resolved = true; + } + return element->evaluate(); + } - auto package = MUST(BAN::RefPtr::create(BAN::move(elements), BAN::move(unresolved_references), context.scope)); - return ParseResult(package); + static ParseResult parse(AML::ParseContext& context, BAN::RefPtr package) + { + BAN::RefPtr element; + if (context.aml_data[0] != 0x00 && AML::NameString::can_parse(context.aml_data)) + { + auto name = AML::NameString::parse(context.aml_data); + if (!name.has_value()) + return ParseResult::Failure; + element = MUST(BAN::RefPtr::create(package, name.value())); + } + else + { + auto element_result = AML::parse_object(context); + if (!element_result.success()) + return ParseResult::Failure; + element = MUST(BAN::RefPtr::create(package, element_result.node())); + } + return ParseResult(element); } virtual void debug_print(int indent) const override { AML_DEBUG_PRINT_INDENT(indent); - AML_DEBUG_PRINT("Package {"); - AML_DEBUG_PRINTLN(""); - for (const auto& element : elements) + AML_DEBUG_PRINTLN("PackageElement {"); + if (!initialized) { - if (element) - element->debug_print(indent + 1); - else - { - AML_DEBUG_PRINT_INDENT(indent + 1); - AML_DEBUG_PRINT("Uninitialized"); - } - AML_DEBUG_PRINTLN(""); + AML_DEBUG_PRINT_INDENT(indent + 1); + AML_DEBUG_PRINT("Uninitialized"); } + else if (!resolved) + { + AML_DEBUG_PRINT_INDENT(indent + 1); + AML_DEBUG_PRINT("Unresolved {}", unresolved_name); + } + else + { + element->debug_print(indent + 1); + } + AML_DEBUG_PRINTLN(""); AML_DEBUG_PRINT_INDENT(indent); AML_DEBUG_PRINT("}"); } diff --git a/kernel/kernel/ACPI/AML/Package.cpp b/kernel/kernel/ACPI/AML/Package.cpp new file mode 100644 index 00000000..eb30f91e --- /dev/null +++ b/kernel/kernel/ACPI/AML/Package.cpp @@ -0,0 +1,57 @@ +#include + +namespace Kernel::ACPI +{ + + AML::ParseResult AML::Package::parse(AML::ParseContext& context) + { + ASSERT(context.aml_data.size() >= 1); + ASSERT(static_cast(context.aml_data[0]) == Byte::PackageOp); + context.aml_data = context.aml_data.slice(1); + + auto package_pkg = AML::parse_pkg(context.aml_data); + if (!package_pkg.has_value()) + return ParseResult::Failure; + + auto package_context = context; + package_context.aml_data = package_pkg.value(); + + if (package_pkg->size() < 1) + return ParseResult::Failure; + uint8_t num_elements = package_context.aml_data[0]; + package_context.aml_data = package_context.aml_data.slice(1); + + auto package = MUST(BAN::RefPtr::create(context.scope)); + while (package->elements.size() < num_elements && package_context.aml_data.size() > 0) + { + auto element_result = PackageElement::parse(package_context, package); + if (!element_result.success()) + return ParseResult::Failure; + ASSERT(element_result.node() && element_result.node()->type == Node::Type::PackageElement); + auto element = static_cast(element_result.node().ptr()); + MUST(package->elements.push_back(element)); + } + while (package->elements.size() < num_elements) + { + auto uninitialized = MUST(BAN::RefPtr::create(package)); + MUST(package->elements.push_back(uninitialized)); + } + + return ParseResult(package); + } + + void AML::Package::debug_print(int indent) const + { + AML_DEBUG_PRINT_INDENT(indent); + AML_DEBUG_PRINT("Package {"); + AML_DEBUG_PRINTLN(""); + for (const auto& element : elements) + { + element->debug_print(indent + 1); + AML_DEBUG_PRINTLN(""); + } + AML_DEBUG_PRINT_INDENT(indent); + AML_DEBUG_PRINT("}"); + } + +}