Kernel: Rework AML package and implement indexing in to packages

This commit is contained in:
Bananymous 2024-04-19 11:26:48 +03:00
parent 0bf45069bd
commit 693f90449f
5 changed files with 162 additions and 78 deletions

View File

@ -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

View File

@ -2,6 +2,7 @@
#include <kernel/ACPI/AML/Buffer.h>
#include <kernel/ACPI/AML/Node.h>
#include <kernel/ACPI/AML/Package.h>
#include <kernel/ACPI/AML/ParseContext.h>
#include <kernel/ACPI/AML/Reference.h>
@ -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<AML::Package*>(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<AML::Reference>::create(package_element));
break;
}
case AML::Node::Type::String:
AML_TODO("IndexOp source String");
return ParseResult::Failure;

View File

@ -28,6 +28,7 @@ namespace Kernel::ACPI::AML
Namespace,
OpRegion,
Package,
PackageElement,
PowerResource,
Processor,
Reference,

View File

@ -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<UnresolvedReference> unresolved_references;
AML::NameString scope; // Used for resolving references
BAN::Vector<BAN::RefPtr<PackageElement>> elements;
AML::NameString scope;
BAN::Vector<BAN::RefPtr<AML::Node>> elements;
Package(BAN::Vector<BAN::RefPtr<AML::Node>>&& elements, BAN::Vector<UnresolvedReference>&& 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<AML::Node> 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<AML::Package> parent;
BAN::RefPtr<AML::Node> element;
AML::NameString unresolved_name;
bool resolved = false;
bool initialized = false;
PackageElement(BAN::RefPtr<AML::Package> parent, BAN::RefPtr<AML::Node> element)
: Node(Node::Type::PackageElement)
, parent(parent)
, element(element)
{
ASSERT(context.aml_data.size() >= 1);
ASSERT(static_cast<Byte>(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<AML::Package> 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<AML::Package> 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<BAN::RefPtr<AML::Node>> elements;
BAN::Vector<UnresolvedReference> unresolved_references;
while (elements.size() < num_elements && package_context.aml_data.size() > 0)
BAN::RefPtr<AML::Node> evaluate() override
{
if (!initialized)
{
BAN::RefPtr<AML::Node> 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<AML::Node>()));
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<Package>::create(BAN::move(elements), BAN::move(unresolved_references), context.scope));
return ParseResult(package);
static ParseResult parse(AML::ParseContext& context, BAN::RefPtr<AML::Package> package)
{
BAN::RefPtr<AML::PackageElement> 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<PackageElement>::create(package, name.value()));
}
else
{
auto element_result = AML::parse_object(context);
if (!element_result.success())
return ParseResult::Failure;
element = MUST(BAN::RefPtr<PackageElement>::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("}");
}

View File

@ -0,0 +1,57 @@
#include <kernel/ACPI/AML/Package.h>
namespace Kernel::ACPI
{
AML::ParseResult AML::Package::parse(AML::ParseContext& context)
{
ASSERT(context.aml_data.size() >= 1);
ASSERT(static_cast<Byte>(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<Package>::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<PackageElement*>(element_result.node().ptr());
MUST(package->elements.push_back(element));
}
while (package->elements.size() < num_elements)
{
auto uninitialized = MUST(BAN::RefPtr<PackageElement>::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("}");
}
}