forked from Bananymous/banan-os
Kernel: Implement more features for AML parser/interpreter
Added - BankField - BufferField - PowerResource - ThermalZone - Reference - Package element forward declare
This commit is contained in:
parent
93ddee5956
commit
afb1d7ef0c
|
@ -1,6 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <kernel/ACPI/AML/Bytes.h>
|
||||
#include <kernel/ACPI/AML/Integer.h>
|
||||
#include <kernel/ACPI/AML/Node.h>
|
||||
#include <kernel/ACPI/AML/ParseContext.h>
|
||||
#include <kernel/ACPI/AML/Pkg.h>
|
||||
|
@ -12,7 +13,14 @@ namespace Kernel::ACPI::AML
|
|||
{
|
||||
BAN::Vector<uint8_t> buffer;
|
||||
|
||||
Buffer() : AML::Node(Node::Type::Buffer) {}
|
||||
Buffer()
|
||||
: AML::Node(Node::Type::Buffer)
|
||||
{}
|
||||
|
||||
BAN::RefPtr<AML::Node> evaluate() override
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
static ParseResult parse(AML::ParseContext& context)
|
||||
{
|
||||
|
@ -57,4 +65,147 @@ namespace Kernel::ACPI::AML
|
|||
}
|
||||
};
|
||||
|
||||
struct BufferField : AML::NamedObject
|
||||
{
|
||||
BAN::RefPtr<Buffer> buffer;
|
||||
size_t field_bit_offset;
|
||||
size_t field_bit_size;
|
||||
|
||||
BufferField(AML::NameSeg name, BAN::RefPtr<Buffer> buffer, size_t field_bit_offset, size_t field_bit_size)
|
||||
: AML::NamedObject(Node::Type::BufferField, name)
|
||||
, buffer(buffer)
|
||||
, field_bit_offset(field_bit_offset)
|
||||
, field_bit_size(field_bit_size)
|
||||
{}
|
||||
|
||||
BAN::RefPtr<AML::Node> evaluate() override
|
||||
{
|
||||
ASSERT(buffer);
|
||||
ASSERT(field_bit_offset + field_bit_size <= buffer->buffer.size() * 8);
|
||||
|
||||
uint64_t value = 0;
|
||||
if (field_bit_size == 1)
|
||||
{
|
||||
size_t byte_offset = field_bit_offset / 8;
|
||||
size_t bit_offset = field_bit_offset % 8;
|
||||
value = (buffer->buffer[byte_offset] >> bit_offset) & 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
ASSERT(field_bit_size % 8 == 0);
|
||||
for (size_t byte = 0; byte < field_bit_size / 8; byte++)
|
||||
value |= buffer->buffer[byte] << byte;
|
||||
}
|
||||
|
||||
return MUST(BAN::RefPtr<AML::Integer>::create(value));
|
||||
}
|
||||
|
||||
bool store(BAN::RefPtr<AML::Node> node) override
|
||||
{
|
||||
ASSERT(buffer);
|
||||
ASSERT(field_bit_offset + field_bit_size <= buffer->buffer.size() * 8);
|
||||
|
||||
auto value = node->as_integer();
|
||||
if (!value.has_value())
|
||||
return false;
|
||||
|
||||
if (field_bit_size == 1)
|
||||
{
|
||||
size_t byte_offset = field_bit_offset / 8;
|
||||
size_t bit_offset = field_bit_offset % 8;
|
||||
buffer->buffer[byte_offset] &= ~(1 << bit_offset);
|
||||
buffer->buffer[byte_offset] |= (value.value() & 1) << bit_offset;
|
||||
}
|
||||
else
|
||||
{
|
||||
ASSERT(field_bit_size % 8 == 0);
|
||||
for (size_t byte = 0; byte < field_bit_size / 8; byte++)
|
||||
buffer->buffer[byte] = (value.value() >> (byte * 8)) & 0xFF;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static ParseResult parse(AML::ParseContext& context)
|
||||
{
|
||||
ASSERT(context.aml_data.size() >= 1);
|
||||
|
||||
size_t field_bit_size = 0;
|
||||
switch (static_cast<Byte>(context.aml_data[0]))
|
||||
{
|
||||
case AML::Byte::CreateBitFieldOp:
|
||||
field_bit_size = 1;
|
||||
break;
|
||||
case AML::Byte::CreateByteFieldOp:
|
||||
field_bit_size = 8;
|
||||
break;
|
||||
case AML::Byte::CreateWordFieldOp:
|
||||
field_bit_size = 16;
|
||||
break;
|
||||
case AML::Byte::CreateDWordFieldOp:
|
||||
field_bit_size = 32;
|
||||
break;
|
||||
case AML::Byte::CreateQWordFieldOp:
|
||||
field_bit_size = 64;
|
||||
break;
|
||||
default:
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
context.aml_data = context.aml_data.slice(1);
|
||||
|
||||
auto buffer_result = AML::parse_object(context);
|
||||
if (!buffer_result.success())
|
||||
return ParseResult::Failure;
|
||||
auto buffer_node = buffer_result.node() ? buffer_result.node()->evaluate() : nullptr;
|
||||
if (!buffer_node || buffer_node->type != Node::Type::Buffer)
|
||||
{
|
||||
AML_ERROR("Buffer source does not evaluate to a Buffer");
|
||||
return ParseResult::Failure;
|
||||
}
|
||||
auto buffer = static_cast<Buffer*>(buffer_node.ptr());
|
||||
|
||||
auto index_result = AML::parse_object(context);
|
||||
if (!index_result.success())
|
||||
return ParseResult::Failure;
|
||||
auto index = index_result.node() ? index_result.node()->as_integer() : BAN::Optional<uint64_t>();
|
||||
if (!index.has_value())
|
||||
{
|
||||
AML_ERROR("Failed to parse index for BufferField");
|
||||
return ParseResult::Failure;
|
||||
}
|
||||
size_t field_bit_offset = index.value();
|
||||
if (field_bit_size != 1)
|
||||
field_bit_offset *= 8;
|
||||
|
||||
auto field_name = AML::NameString::parse(context.aml_data);
|
||||
if (!field_name.has_value())
|
||||
return ParseResult::Failure;
|
||||
if (field_name->path.empty())
|
||||
{
|
||||
AML_ERROR("Empty field name for BufferField");
|
||||
return ParseResult::Failure;
|
||||
}
|
||||
|
||||
auto field = MUST(BAN::RefPtr<BufferField>::create(field_name->path.back(), buffer, field_bit_offset, field_bit_size));
|
||||
if (!Namespace::root_namespace()->add_named_object(context, field_name.value(), field))
|
||||
return ParseResult::Failure;
|
||||
|
||||
#if AML_DEBUG_LEVEL >= 2
|
||||
field->debug_print(0);
|
||||
AML_DEBUG_PRINTLN("");
|
||||
#endif
|
||||
|
||||
return ParseResult::Success;
|
||||
}
|
||||
|
||||
virtual void debug_print(int indent) const override
|
||||
{
|
||||
AML_DEBUG_PRINT_INDENT(indent);
|
||||
AML_DEBUG_PRINT("BufferField {} at bit offset {} ({} bits) to { ", name, field_bit_offset, field_bit_size);
|
||||
buffer->debug_print(0);
|
||||
AML_DEBUG_PRINT(" }");
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -35,6 +35,16 @@ namespace Kernel::ACPI::AML
|
|||
WriteAsZeros = 2,
|
||||
};
|
||||
UpdateRule update_rule;
|
||||
|
||||
enum class AccessAttrib
|
||||
{
|
||||
Normal = 0,
|
||||
Bytes = 1,
|
||||
RawBytes = 2,
|
||||
RawProcessBytes = 3,
|
||||
};
|
||||
AccessAttrib access_attrib = AccessAttrib::Normal;
|
||||
uint8_t access_length = 0;
|
||||
};
|
||||
|
||||
struct FieldElement : public NamedObject
|
||||
|
@ -98,4 +108,30 @@ namespace Kernel::ACPI::AML
|
|||
static ParseResult parse(ParseContext& context);
|
||||
};
|
||||
|
||||
struct BankFieldElement : public NamedObject
|
||||
{
|
||||
uint64_t bit_offset;
|
||||
uint64_t bit_count;
|
||||
|
||||
FieldRules access_rules;
|
||||
|
||||
BAN::RefPtr<OpRegion> op_region;
|
||||
BAN::RefPtr<NamedObject> bank_selector;
|
||||
uint64_t bank_value;
|
||||
|
||||
BankFieldElement(NameSeg name, uint64_t bit_offset, uint64_t bit_count, FieldRules access_rules)
|
||||
: NamedObject(Node::Type::BankFieldElement, name)
|
||||
, bit_offset(bit_offset)
|
||||
, bit_count(bit_count)
|
||||
, access_rules(access_rules)
|
||||
{}
|
||||
|
||||
void debug_print(int indent) const override;
|
||||
};
|
||||
|
||||
struct BankField
|
||||
{
|
||||
static ParseResult parse(ParseContext& context);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,96 @@
|
|||
#pragma once
|
||||
|
||||
#include <kernel/ACPI/AML/Buffer.h>
|
||||
#include <kernel/ACPI/AML/Node.h>
|
||||
#include <kernel/ACPI/AML/ParseContext.h>
|
||||
#include <kernel/ACPI/AML/Reference.h>
|
||||
|
||||
namespace Kernel::ACPI::AML
|
||||
{
|
||||
|
||||
struct Index
|
||||
{
|
||||
static ParseResult parse(ParseContext& context)
|
||||
{
|
||||
ASSERT(context.aml_data.size() >= 1);
|
||||
ASSERT(static_cast<Byte>(context.aml_data[0]) == Byte::IndexOp);
|
||||
context.aml_data = context.aml_data.slice(1);
|
||||
|
||||
auto source_result = AML::parse_object(context);
|
||||
if (!source_result.success())
|
||||
return ParseResult::Failure;
|
||||
auto source = source_result.node() ? source_result.node()->evaluate() : BAN::RefPtr<AML::Node>();
|
||||
if (!source)
|
||||
{
|
||||
AML_ERROR("IndexOp source is null");
|
||||
return ParseResult::Failure;
|
||||
}
|
||||
|
||||
auto index_result = AML::parse_object(context);
|
||||
if (!index_result.success())
|
||||
return ParseResult::Failure;
|
||||
auto index = index_result.node() ? index_result.node()->as_integer() : BAN::Optional<uint64_t>();
|
||||
if (!index.has_value())
|
||||
{
|
||||
AML_ERROR("IndexOp index is not an integer");
|
||||
return ParseResult::Failure;
|
||||
}
|
||||
|
||||
BAN::RefPtr<AML::Reference> result;
|
||||
switch (source->type)
|
||||
{
|
||||
case AML::Node::Type::Buffer:
|
||||
{
|
||||
auto buffer = static_cast<AML::Buffer*>(source.ptr());
|
||||
if (index.value() >= buffer->buffer.size())
|
||||
{
|
||||
AML_ERROR("IndexOp index is out of buffer bounds");
|
||||
return ParseResult::Failure;
|
||||
}
|
||||
auto buffer_field = MUST(BAN::RefPtr<BufferField>::create(NameSeg(""sv), buffer, index.value() * 8, 8));
|
||||
result = MUST(BAN::RefPtr<AML::Reference>::create(buffer_field));
|
||||
break;
|
||||
}
|
||||
case AML::Node::Type::Package:
|
||||
AML_TODO("IndexOp source Package");
|
||||
return ParseResult::Failure;
|
||||
case AML::Node::Type::String:
|
||||
AML_TODO("IndexOp source String");
|
||||
return ParseResult::Failure;
|
||||
default:
|
||||
AML_ERROR("IndexOp source is not a Buffer, Package, or String");
|
||||
return ParseResult::Failure;
|
||||
}
|
||||
|
||||
#if AML_DEBUG_LEVEL >= 2
|
||||
AML_DEBUG_PRINT("Index {}, ", index.value());
|
||||
source->debug_print(0);
|
||||
AML_DEBUG_PRINTLN("");
|
||||
#endif
|
||||
|
||||
if (context.aml_data.size() < 1)
|
||||
return ParseResult::Failure;
|
||||
|
||||
if (context.aml_data[0] == 0x00)
|
||||
context.aml_data = context.aml_data.slice(1);
|
||||
else
|
||||
{
|
||||
auto destination_result = AML::parse_object(context);
|
||||
if (!destination_result.success())
|
||||
return ParseResult::Failure;
|
||||
auto destination = destination_result.node();
|
||||
if (!destination)
|
||||
{
|
||||
AML_ERROR("IndexOp failed to resolve destination");
|
||||
return ParseResult::Failure;
|
||||
}
|
||||
|
||||
if (!destination->store(result))
|
||||
return ParseResult::Failure;
|
||||
}
|
||||
|
||||
return ParseResult(result);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
|
@ -14,13 +14,16 @@ namespace Kernel::ACPI::AML
|
|||
struct Integer : public Node
|
||||
{
|
||||
static constexpr uint64_t Ones = -1;
|
||||
uint64_t value;
|
||||
const uint64_t value;
|
||||
|
||||
Integer(uint64_t value) : Node(Node::Type::Integer), value(value) {}
|
||||
Integer(uint64_t value)
|
||||
: Node(Node::Type::Integer)
|
||||
, value(value)
|
||||
{}
|
||||
|
||||
BAN::RefPtr<AML::Node> evaluate() override
|
||||
{
|
||||
return MUST(BAN::RefPtr<Integer>::create(value));
|
||||
return this;
|
||||
}
|
||||
|
||||
static ParseResult parse(BAN::ConstByteSpan& aml_data)
|
||||
|
|
|
@ -106,6 +106,23 @@ namespace Kernel::ACPI::AML
|
|||
}
|
||||
}
|
||||
|
||||
static bool can_parse(BAN::ConstByteSpan aml_data)
|
||||
{
|
||||
if (aml_data.size() == 0)
|
||||
return false;
|
||||
switch (static_cast<AML::Byte>(aml_data[0]))
|
||||
{
|
||||
case AML::Byte::RootChar:
|
||||
case AML::Byte::ParentPrefixChar:
|
||||
case AML::Byte::NullName:
|
||||
case AML::Byte::DualNamePrefix:
|
||||
case AML::Byte::MultiNamePrefix:
|
||||
return true;
|
||||
default:
|
||||
return is_lead_name_char(aml_data[0]);
|
||||
}
|
||||
}
|
||||
|
||||
static BAN::Optional<NameString> parse(BAN::ConstByteSpan& aml_data)
|
||||
{
|
||||
if (aml_data.size() == 0)
|
||||
|
|
|
@ -13,7 +13,9 @@ namespace Kernel::ACPI::AML
|
|||
{
|
||||
enum class Type
|
||||
{
|
||||
BankFieldElement,
|
||||
Buffer,
|
||||
BufferField,
|
||||
Device,
|
||||
FieldElement,
|
||||
IndexFieldElement,
|
||||
|
@ -24,9 +26,12 @@ namespace Kernel::ACPI::AML
|
|||
Namespace,
|
||||
OpRegion,
|
||||
Package,
|
||||
PowerResource,
|
||||
Processor,
|
||||
Reference,
|
||||
Register,
|
||||
String,
|
||||
ThermalZone,
|
||||
};
|
||||
const Type type;
|
||||
|
||||
|
@ -35,9 +40,9 @@ namespace Kernel::ACPI::AML
|
|||
|
||||
virtual bool is_scope() const { return false; }
|
||||
|
||||
BAN::Optional<uint64_t> as_integer();
|
||||
virtual BAN::RefPtr<AML::Node> evaluate() { AML_TODO("evaluate, type {}", static_cast<uint8_t>(type)); return nullptr; }
|
||||
virtual bool store(BAN::RefPtr<AML::Node> source) { AML_TODO("store, type {}", static_cast<uint8_t>(type)); return false; }
|
||||
[[nodiscard]] BAN::Optional<uint64_t> as_integer();
|
||||
[[nodiscard]] virtual BAN::RefPtr<AML::Node> evaluate() { AML_TODO("evaluate, type {}", static_cast<uint8_t>(type)); return nullptr; }
|
||||
[[nodiscard]] virtual bool store(BAN::RefPtr<AML::Node> source) { AML_TODO("store, type {}", static_cast<uint8_t>(type)); return false; }
|
||||
|
||||
virtual void debug_print(int indent) const = 0;
|
||||
};
|
||||
|
|
|
@ -10,27 +10,40 @@ namespace Kernel::ACPI::AML
|
|||
|
||||
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<AML::Node>> elements;
|
||||
|
||||
Package() : Node(Node::Type::Package) {}
|
||||
Package(BAN::Vector<BAN::RefPtr<AML::Node>>&& elements, BAN::Vector<UnresolvedReference>&& unresolved_references, 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
|
||||
{
|
||||
BAN::Vector<BAN::RefPtr<AML::Node>> evaluated_elements;
|
||||
for (auto& element : elements)
|
||||
// resolve references
|
||||
for (auto& reference : unresolved_references)
|
||||
{
|
||||
auto evaluated = element->evaluate();
|
||||
if (!evaluated)
|
||||
auto object = Namespace::root_namespace()->find_object(scope, reference.name);
|
||||
if (!object)
|
||||
{
|
||||
AML_ERROR("Failed to evaluate element in package");
|
||||
AML_ERROR("Failed to resolve reference {} in package", reference.name);
|
||||
return {};
|
||||
}
|
||||
evaluated_elements.push_back(evaluated);
|
||||
ASSERT(!elements[reference.index]);
|
||||
elements[reference.index] = object;
|
||||
}
|
||||
unresolved_references.clear();
|
||||
|
||||
auto package = MUST(BAN::RefPtr<Package>::create());
|
||||
package->elements = BAN::move(evaluated_elements);
|
||||
return package;
|
||||
return this;
|
||||
}
|
||||
|
||||
static ParseResult parse(AML::ParseContext& context)
|
||||
|
@ -52,18 +65,33 @@ namespace Kernel::ACPI::AML
|
|||
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)
|
||||
{
|
||||
auto element_result = AML::parse_object(package_context);
|
||||
if (!element_result.success())
|
||||
return ParseResult::Failure;
|
||||
MUST(elements.push_back(element_result.node()));
|
||||
BAN::RefPtr<AML::Node> element;
|
||||
|
||||
// Store name strings as references
|
||||
if (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));
|
||||
}
|
||||
while (elements.size() < num_elements)
|
||||
MUST(elements.push_back(BAN::RefPtr<AML::Node>()));
|
||||
|
||||
auto package = MUST(BAN::RefPtr<Package>::create());
|
||||
package->elements = BAN::move(elements);
|
||||
auto package = MUST(BAN::RefPtr<Package>::create(BAN::move(elements), BAN::move(unresolved_references), context.scope));
|
||||
return ParseResult(package);
|
||||
}
|
||||
|
||||
|
@ -74,7 +102,11 @@ namespace Kernel::ACPI::AML
|
|||
AML_DEBUG_PRINTLN("");
|
||||
for (const auto& element : elements)
|
||||
{
|
||||
element->debug_print(indent + 1);
|
||||
AML_DEBUG_PRINT_INDENT(indent + 1);
|
||||
if (element)
|
||||
element->debug_print(0);
|
||||
else
|
||||
AML_DEBUG_PRINT("Uninitialized");
|
||||
AML_DEBUG_PRINTLN("");
|
||||
}
|
||||
AML_DEBUG_PRINT_INDENT(indent);
|
||||
|
|
|
@ -0,0 +1,68 @@
|
|||
#pragma once
|
||||
|
||||
#include <BAN/Endianness.h>
|
||||
#include <kernel/ACPI/AML/Bytes.h>
|
||||
#include <kernel/ACPI/AML/ParseContext.h>
|
||||
#include <kernel/ACPI/AML/Pkg.h>
|
||||
#include <kernel/ACPI/AML/Scope.h>
|
||||
|
||||
namespace Kernel::ACPI::AML
|
||||
{
|
||||
|
||||
struct PowerResource : public AML::Scope
|
||||
{
|
||||
uint8_t system_level;
|
||||
uint16_t resource_order;
|
||||
|
||||
PowerResource(NameSeg name, uint8_t system_level, uint16_t resource_order)
|
||||
: Scope(Node::Type::PowerResource, name)
|
||||
, system_level(system_level)
|
||||
, resource_order(resource_order)
|
||||
{}
|
||||
|
||||
static ParseResult parse(ParseContext& context)
|
||||
{
|
||||
ASSERT(context.aml_data.size() >= 2);
|
||||
ASSERT(static_cast<AML::Byte>(context.aml_data[0]) == AML::Byte::ExtOpPrefix);
|
||||
ASSERT(static_cast<AML::ExtOp>(context.aml_data[1]) == AML::ExtOp::PowerResOp);
|
||||
context.aml_data = context.aml_data.slice(2);
|
||||
|
||||
auto opt_power_res_pkg = AML::parse_pkg(context.aml_data);
|
||||
if (!opt_power_res_pkg.has_value())
|
||||
return ParseResult::Failure;
|
||||
auto power_res_pkg = opt_power_res_pkg.value();
|
||||
|
||||
auto name = NameString::parse(power_res_pkg);
|
||||
if (!name.has_value())
|
||||
return ParseResult::Failure;
|
||||
|
||||
if (power_res_pkg.size() < 1)
|
||||
return ParseResult::Failure;
|
||||
uint8_t system_level = power_res_pkg[0];
|
||||
power_res_pkg = power_res_pkg.slice(1);
|
||||
|
||||
if (power_res_pkg.size() < 2)
|
||||
return ParseResult::Failure;
|
||||
uint16_t resource_order = BAN::little_endian_to_host<uint16_t>(*reinterpret_cast<const uint16_t*>(power_res_pkg.data()));
|
||||
power_res_pkg = power_res_pkg.slice(2);
|
||||
|
||||
auto power_res = MUST(BAN::RefPtr<PowerResource>::create(name->path.back(), system_level, resource_order));
|
||||
if (!Namespace::root_namespace()->add_named_object(context, name.value(), power_res))
|
||||
return ParseResult::Failure;
|
||||
|
||||
#if AML_DEBUG_LEVEL >= 2
|
||||
power_res->debug_print(0);
|
||||
AML_DEBUG_PRINTLN("");
|
||||
#endif
|
||||
|
||||
return power_res->enter_context_and_parse_term_list(context, name.value(), power_res_pkg);
|
||||
}
|
||||
|
||||
virtual void debug_print(int indent) const override
|
||||
{
|
||||
AML_DEBUG_PRINT_INDENT(indent);
|
||||
AML_DEBUG_PRINT("PowerResource {} (SystemLevel {}, ResourceOrder {})", name, system_level, resource_order);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
|
@ -29,42 +29,46 @@ namespace Kernel::ACPI::AML
|
|||
ASSERT(static_cast<AML::ExtOp>(context.aml_data[1]) == AML::ExtOp::ProcessorOp);
|
||||
context.aml_data = context.aml_data.slice(2);
|
||||
|
||||
auto processor_pkg = AML::parse_pkg(context.aml_data);
|
||||
if (!processor_pkg.has_value())
|
||||
auto opt_processor_pkg = AML::parse_pkg(context.aml_data);
|
||||
if (!opt_processor_pkg.has_value())
|
||||
return ParseResult::Failure;
|
||||
auto processor_pkg = opt_processor_pkg.value();
|
||||
|
||||
auto name = NameString::parse(processor_pkg.value());
|
||||
auto name = NameString::parse(processor_pkg);
|
||||
if (!name.has_value())
|
||||
return ParseResult::Failure;
|
||||
|
||||
if (processor_pkg->size() < 1)
|
||||
if (processor_pkg.size() < 1)
|
||||
return ParseResult::Failure;
|
||||
uint8_t id = processor_pkg.value()[0];
|
||||
processor_pkg = processor_pkg->slice(1);
|
||||
uint8_t id = processor_pkg[0];
|
||||
processor_pkg = processor_pkg.slice(1);
|
||||
|
||||
if (processor_pkg->size() < 4)
|
||||
if (processor_pkg.size() < 4)
|
||||
return ParseResult::Failure;
|
||||
uint32_t pblk_addr = BAN::little_endian_to_host<uint32_t>(*reinterpret_cast<const uint32_t*>(processor_pkg->data()));
|
||||
processor_pkg = processor_pkg->slice(4);
|
||||
uint32_t pblk_addr = BAN::little_endian_to_host<uint32_t>(*reinterpret_cast<const uint32_t*>(processor_pkg.data()));
|
||||
processor_pkg = processor_pkg.slice(4);
|
||||
|
||||
if (processor_pkg->size() < 1)
|
||||
if (processor_pkg.size() < 1)
|
||||
return ParseResult::Failure;
|
||||
uint8_t pblk_len = processor_pkg.value()[0];
|
||||
processor_pkg = processor_pkg->slice(1);
|
||||
uint8_t pblk_len = processor_pkg[0];
|
||||
processor_pkg = processor_pkg.slice(1);
|
||||
|
||||
auto processor = MUST(BAN::RefPtr<Processor>::create(name->path.back(), id, pblk_addr, pblk_len));
|
||||
if (!Namespace::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());
|
||||
#if AML_DEBUG_LEVEL >= 2
|
||||
processor->debug_print(0);
|
||||
AML_DEBUG_PRINTLN("");
|
||||
#endif
|
||||
|
||||
return processor->enter_context_and_parse_term_list(context, name.value(), processor_pkg);
|
||||
}
|
||||
|
||||
virtual void debug_print(int indent) const override
|
||||
{
|
||||
AML_DEBUG_PRINT_INDENT(indent);
|
||||
AML_DEBUG_PRINT("Processor ");
|
||||
name.debug_print();
|
||||
AML_DEBUG_PRINT(" (ID: {}, PBlkAddr: 0x{H}, PBlkLen: {})", id, pblk_addr, pblk_len);
|
||||
AML_DEBUG_PRINT("Processor {} (ID: {}, PBlkAddr: 0x{H}, PBlkLen: {})", name, id, pblk_addr, pblk_len);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -0,0 +1,155 @@
|
|||
#pragma once
|
||||
|
||||
#include <kernel/ACPI/AML/Bytes.h>
|
||||
#include <kernel/ACPI/AML/Integer.h>
|
||||
#include <kernel/ACPI/AML/Node.h>
|
||||
#include <kernel/ACPI/AML/Names.h>
|
||||
#include <kernel/ACPI/AML/String.h>
|
||||
#include <kernel/ACPI/AML/ParseContext.h>
|
||||
|
||||
namespace Kernel::ACPI::AML
|
||||
{
|
||||
|
||||
struct Reference : public AML::Node
|
||||
{
|
||||
BAN::RefPtr<AML::Node> node;
|
||||
|
||||
Reference(BAN::RefPtr<AML::Node> node)
|
||||
: Node(AML::Node::Type::Reference)
|
||||
, node(node)
|
||||
{
|
||||
ASSERT(node);
|
||||
}
|
||||
|
||||
BAN::RefPtr<AML::Node> evaluate() override
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
static ParseResult parse(ParseContext& context)
|
||||
{
|
||||
ASSERT(context.aml_data.size() >= 1);
|
||||
|
||||
bool conditional = false;
|
||||
switch (static_cast<AML::Byte>(context.aml_data[0]))
|
||||
{
|
||||
case AML::Byte::DerefOfOp:
|
||||
return parse_dereference(context);
|
||||
case AML::Byte::RefOfOp:
|
||||
context.aml_data = context.aml_data.slice(1);
|
||||
conditional = false;
|
||||
break;
|
||||
case AML::Byte::ExtOpPrefix:
|
||||
ASSERT(static_cast<AML::ExtOp>(context.aml_data[1]) == AML::ExtOp::CondRefOfOp);
|
||||
context.aml_data = context.aml_data.slice(2);
|
||||
conditional = true;
|
||||
break;
|
||||
default:
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
BAN::RefPtr<AML::Node> object;
|
||||
if (NameString::can_parse(context.aml_data))
|
||||
{
|
||||
auto name = NameString::parse(context.aml_data);
|
||||
if (!name.has_value())
|
||||
return ParseResult::Failure;
|
||||
object = Namespace::root_namespace()->find_object(context.scope, name.value());
|
||||
}
|
||||
else
|
||||
{
|
||||
auto parse_result = AML::parse_object(context);
|
||||
if (!parse_result.success())
|
||||
return ParseResult::Failure;
|
||||
object = parse_result.node();
|
||||
}
|
||||
|
||||
if (!conditional)
|
||||
{
|
||||
if (!object)
|
||||
{
|
||||
AML_ERROR("RefOf failed to resolve reference");
|
||||
return ParseResult::Failure;
|
||||
}
|
||||
auto reference = MUST(BAN::RefPtr<Reference>::create(object));
|
||||
#if AML_DEBUG_LEVEL >= 2
|
||||
reference->debug_print(0);
|
||||
AML_DEBUG_PRINTLN("");
|
||||
#endif
|
||||
return ParseResult(reference);
|
||||
}
|
||||
|
||||
if (context.aml_data.size() >= 1 && context.aml_data[0] != 0x00)
|
||||
{
|
||||
auto target_result = AML::parse_object(context);
|
||||
if (!target_result.success())
|
||||
return ParseResult::Failure;
|
||||
auto target_node = target_result.node();
|
||||
if (!target_node)
|
||||
{
|
||||
AML_ERROR("CondRefOf failed to resolve target");
|
||||
return ParseResult::Failure;
|
||||
}
|
||||
target_node->store(MUST(BAN::RefPtr<Reference>::create(object)));
|
||||
}
|
||||
|
||||
#if AML_DEBUG_LEVEL >= 2
|
||||
AML_DEBUG_PRINT("CondRefOf ");
|
||||
if (object)
|
||||
object->debug_print(0);
|
||||
else
|
||||
AML_DEBUG_PRINT("null");
|
||||
AML_DEBUG_PRINTLN("");
|
||||
#endif
|
||||
|
||||
auto return_value = MUST(BAN::RefPtr<Integer>::create(object ? Integer::Ones : 0));
|
||||
return AML::ParseResult(return_value);
|
||||
}
|
||||
|
||||
static ParseResult parse_dereference(ParseContext& context)
|
||||
{
|
||||
ASSERT(context.aml_data.size() >= 1);
|
||||
ASSERT(static_cast<Byte>(context.aml_data[0]) == Byte::DerefOfOp);
|
||||
context.aml_data = context.aml_data.slice(1);
|
||||
|
||||
if (context.aml_data.size() >= 1 && static_cast<AML::Byte>(context.aml_data[0]) == AML::Byte::StringPrefix)
|
||||
{
|
||||
auto string_result = AML::String::parse(context);
|
||||
if (!string_result.success())
|
||||
return ParseResult::Failure;
|
||||
ASSERT(string_result.node());
|
||||
auto string = static_cast<AML::String*>(string_result.node().ptr());
|
||||
AML_TODO("DerefOf String ({})", string->string);
|
||||
return ParseResult::Failure;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto parse_result = AML::parse_object(context);
|
||||
if (!parse_result.success())
|
||||
return ParseResult::Failure;
|
||||
auto object = parse_result.node();
|
||||
if (!object || object->type != AML::Node::Type::Reference)
|
||||
{
|
||||
AML_TODO("DerefOf source is not a Reference, but a {}", object ? static_cast<uint8_t>(object->type) : 999);
|
||||
return ParseResult::Failure;
|
||||
}
|
||||
#if AML_DEBUG_LEVEL >= 2
|
||||
AML_DEBUG_PRINT("DerefOf ");
|
||||
object->debug_print(0);
|
||||
AML_DEBUG_PRINTLN("");
|
||||
#endif
|
||||
return ParseResult(static_cast<Reference*>(object.ptr())->node);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void debug_print(int indent) const override
|
||||
{
|
||||
AML_DEBUG_PRINT_INDENT(indent);
|
||||
AML_DEBUG_PRINTLN("Reference {");
|
||||
node->debug_print(indent + 1);
|
||||
AML_DEBUG_PRINT_INDENT(indent);
|
||||
AML_DEBUG_PRINT("}");
|
||||
}
|
||||
};
|
||||
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
#pragma once
|
||||
|
||||
#include <BAN/Endianness.h>
|
||||
#include <kernel/ACPI/AML/Bytes.h>
|
||||
#include <kernel/ACPI/AML/ParseContext.h>
|
||||
#include <kernel/ACPI/AML/Pkg.h>
|
||||
#include <kernel/ACPI/AML/Scope.h>
|
||||
|
||||
namespace Kernel::ACPI::AML
|
||||
{
|
||||
|
||||
struct ThermalZone : public AML::Scope
|
||||
{
|
||||
ThermalZone(NameSeg name)
|
||||
: Scope(Node::Type::ThermalZone, name)
|
||||
{}
|
||||
|
||||
static ParseResult parse(ParseContext& context)
|
||||
{
|
||||
ASSERT(context.aml_data.size() >= 2);
|
||||
ASSERT(static_cast<AML::Byte>(context.aml_data[0]) == AML::Byte::ExtOpPrefix);
|
||||
ASSERT(static_cast<AML::ExtOp>(context.aml_data[1]) == AML::ExtOp::PowerResOp);
|
||||
context.aml_data = context.aml_data.slice(2);
|
||||
|
||||
auto opt_thermal_zone_pkg = AML::parse_pkg(context.aml_data);
|
||||
if (!opt_thermal_zone_pkg.has_value())
|
||||
return ParseResult::Failure;
|
||||
auto thermal_zone_pkg = opt_thermal_zone_pkg.value();
|
||||
|
||||
auto name = NameString::parse(thermal_zone_pkg);
|
||||
if (!name.has_value())
|
||||
return ParseResult::Failure;
|
||||
|
||||
auto thermal_zone = MUST(BAN::RefPtr<ThermalZone>::create(name->path.back()));
|
||||
if (!Namespace::root_namespace()->add_named_object(context, name.value(), thermal_zone))
|
||||
return ParseResult::Failure;
|
||||
|
||||
#if AML_DEBUG_LEVEL >= 2
|
||||
thermal_zone->debug_print(0);
|
||||
AML_DEBUG_PRINTLN("");
|
||||
#endif
|
||||
|
||||
return thermal_zone->enter_context_and_parse_term_list(context, name.value(), thermal_zone_pkg);
|
||||
}
|
||||
|
||||
virtual void debug_print(int indent) const override
|
||||
{
|
||||
AML_DEBUG_PRINT_INDENT(indent);
|
||||
AML_DEBUG_PRINT("ThermalZone {}", name);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
|
@ -607,4 +607,100 @@ namespace Kernel::ACPI
|
|||
);
|
||||
}
|
||||
|
||||
AML::ParseResult AML::BankField::parse(ParseContext& context)
|
||||
{
|
||||
// BankFieldOp PkgLength NameString NameString BankValue FieldFlags FieldList
|
||||
|
||||
ASSERT(context.aml_data.size() >= 2);
|
||||
ASSERT(static_cast<AML::Byte>(context.aml_data[0]) == AML::Byte::ExtOpPrefix);
|
||||
ASSERT(static_cast<AML::ExtOp>(context.aml_data[1]) == AML::ExtOp::BankFieldOp);
|
||||
context.aml_data = context.aml_data.slice(2);
|
||||
|
||||
auto opt_field_pkg = AML::parse_pkg(context.aml_data);
|
||||
if (!opt_field_pkg.has_value())
|
||||
return ParseResult::Failure;
|
||||
auto field_pkg = opt_field_pkg.release_value();
|
||||
|
||||
auto op_region_name = NameString::parse(field_pkg);
|
||||
if (!op_region_name.has_value())
|
||||
return ParseResult::Failure;
|
||||
auto op_region = Namespace::root_namespace()->find_object(context.scope, op_region_name.value());
|
||||
if (!op_region || op_region->type != AML::Node::Type::OpRegion)
|
||||
{
|
||||
AML_ERROR("BankField RegionName {} does not name a valid OpRegion", op_region_name.value());
|
||||
return ParseResult::Failure;
|
||||
}
|
||||
|
||||
auto bank_selector_name = NameString::parse(field_pkg);
|
||||
if (!bank_selector_name.has_value())
|
||||
return ParseResult::Failure;
|
||||
auto bank_selector = Namespace::root_namespace()->find_object(context.scope, bank_selector_name.value());
|
||||
if (!bank_selector)
|
||||
{
|
||||
AML_ERROR("BankField BankSelector {} does not name a valid object", bank_selector_name.value());
|
||||
return ParseResult::Failure;
|
||||
}
|
||||
|
||||
auto temp_aml_data = context.aml_data;
|
||||
context.aml_data = field_pkg;
|
||||
auto bank_value_result = AML::parse_object(context);
|
||||
field_pkg = context.aml_data;
|
||||
context.aml_data = temp_aml_data;
|
||||
if (!bank_value_result.success())
|
||||
return ParseResult::Failure;
|
||||
auto bank_value = bank_value_result.node() ? bank_value_result.node()->as_integer() : BAN::Optional<uint64_t>();
|
||||
if (!bank_value.has_value())
|
||||
{
|
||||
AML_ERROR("BankField BankValue is not an integer");
|
||||
return ParseResult::Failure;
|
||||
}
|
||||
|
||||
if (field_pkg.size() < 1)
|
||||
return ParseResult::Failure;
|
||||
auto field_flags = field_pkg[0];
|
||||
field_pkg = field_pkg.slice(1);
|
||||
|
||||
ParseFieldElementContext<BankFieldElement> field_context;
|
||||
field_context.field_rules.access_type = static_cast<FieldRules::AccessType>(field_flags & 0x0F);
|
||||
field_context.field_rules.lock_rule = static_cast<FieldRules::LockRule>((field_flags >> 4) & 0x01);
|
||||
field_context.field_rules.update_rule = static_cast<FieldRules::UpdateRule>((field_flags >> 5) & 0x03);
|
||||
field_context.field_bit_offset = 0;
|
||||
field_context.field_pkg = field_pkg;
|
||||
while (field_context.field_pkg.size() > 0)
|
||||
if (!parse_field_element(field_context))
|
||||
return ParseResult::Failure;
|
||||
|
||||
for (auto& [_, element] : field_context.elements)
|
||||
{
|
||||
element->op_region = static_cast<OpRegion*>(op_region.ptr());
|
||||
element->bank_selector = bank_selector;
|
||||
element->bank_value = bank_value.value();
|
||||
|
||||
NameString element_name;
|
||||
MUST(element_name.path.push_back(element->name));
|
||||
if (!Namespace::root_namespace()->add_named_object(context, element_name, element))
|
||||
return ParseResult::Failure;
|
||||
|
||||
#if AML_DEBUG_LEVEL >= 2
|
||||
element->debug_print(0);
|
||||
AML_DEBUG_PRINTLN("");
|
||||
#endif
|
||||
}
|
||||
|
||||
return ParseResult::Success;
|
||||
}
|
||||
|
||||
void AML::BankFieldElement::debug_print(int indent) const
|
||||
{
|
||||
AML_DEBUG_PRINT_INDENT(indent);
|
||||
AML_DEBUG_PRINT("BankFieldElement {} ({}, offset {}, OpRegion {}, BankSelector {}, BankValue {H})",
|
||||
name,
|
||||
bit_count,
|
||||
bit_offset,
|
||||
op_region->name,
|
||||
bank_selector->name,
|
||||
bank_value
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -33,12 +33,8 @@ namespace Kernel::ACPI
|
|||
void AML::Name::debug_print(int indent) const
|
||||
{
|
||||
AML_DEBUG_PRINT_INDENT(indent);
|
||||
AML_DEBUG_PRINT("Name ");
|
||||
name.debug_print();
|
||||
AML_DEBUG_PRINTLN(" {");
|
||||
object->debug_print(indent + 1);
|
||||
AML_DEBUG_PRINTLN("");
|
||||
AML_DEBUG_PRINT_INDENT(indent);
|
||||
AML_DEBUG_PRINT("Name {} { ", name);
|
||||
object->debug_print(0);
|
||||
AML_DEBUG_PRINT("}");
|
||||
}
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include <kernel/ACPI/AML/Expression.h>
|
||||
#include <kernel/ACPI/AML/Field.h>
|
||||
#include <kernel/ACPI/AML/IfElse.h>
|
||||
#include <kernel/ACPI/AML/Index.h>
|
||||
#include <kernel/ACPI/AML/Integer.h>
|
||||
#include <kernel/ACPI/AML/Method.h>
|
||||
#include <kernel/ACPI/AML/Mutex.h>
|
||||
|
@ -11,10 +12,13 @@
|
|||
#include <kernel/ACPI/AML/Node.h>
|
||||
#include <kernel/ACPI/AML/Package.h>
|
||||
#include <kernel/ACPI/AML/ParseContext.h>
|
||||
#include <kernel/ACPI/AML/PowerResource.h>
|
||||
#include <kernel/ACPI/AML/Processor.h>
|
||||
#include <kernel/ACPI/AML/Reference.h>
|
||||
#include <kernel/ACPI/AML/Region.h>
|
||||
#include <kernel/ACPI/AML/Store.h>
|
||||
#include <kernel/ACPI/AML/String.h>
|
||||
#include <kernel/ACPI/AML/ThermalZone.h>
|
||||
#include <kernel/ACPI/AML/Utils.h>
|
||||
|
||||
namespace Kernel::ACPI
|
||||
|
@ -31,7 +35,7 @@ namespace Kernel::ACPI
|
|||
if (!evaluated)
|
||||
return {};
|
||||
if (evaluated->type == Type::Integer)
|
||||
return static_cast<const Integer*>(this)->value;
|
||||
return static_cast<const Integer*>(evaluated.ptr())->value;
|
||||
return {};
|
||||
}
|
||||
|
||||
|
@ -51,6 +55,8 @@ namespace Kernel::ACPI
|
|||
return AML::Field::parse(context);
|
||||
case AML::ExtOp::IndexFieldOp:
|
||||
return AML::IndexField::parse(context);
|
||||
case AML::ExtOp::BankFieldOp:
|
||||
return AML::BankField::parse(context);
|
||||
case AML::ExtOp::OpRegionOp:
|
||||
return AML::OpRegion::parse(context);
|
||||
case AML::ExtOp::DeviceOp:
|
||||
|
@ -61,6 +67,12 @@ namespace Kernel::ACPI
|
|||
return AML::Mutex::parse(context);
|
||||
case AML::ExtOp::ProcessorOp:
|
||||
return AML::Processor::parse(context);
|
||||
case AML::ExtOp::PowerResOp:
|
||||
return AML::PowerResource::parse(context);
|
||||
case AML::ExtOp::ThermalZoneOp:
|
||||
return AML::ThermalZone::parse(context);
|
||||
case AML::ExtOp::CondRefOfOp:
|
||||
return AML::Reference::parse(context);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -128,6 +140,12 @@ namespace Kernel::ACPI
|
|||
case AML::Byte::SubtractOp:
|
||||
case AML::Byte::XorOp:
|
||||
return AML::Expression::parse(context);
|
||||
case AML::Byte::CreateBitFieldOp:
|
||||
case AML::Byte::CreateByteFieldOp:
|
||||
case AML::Byte::CreateWordFieldOp:
|
||||
case AML::Byte::CreateDWordFieldOp:
|
||||
case AML::Byte::CreateQWordFieldOp:
|
||||
return AML::BufferField::parse(context);
|
||||
case AML::Byte::NameOp:
|
||||
return AML::Name::parse(context);
|
||||
case AML::Byte::PackageOp:
|
||||
|
@ -142,6 +160,11 @@ namespace Kernel::ACPI
|
|||
return AML::IfElse::parse(context);
|
||||
case AML::Byte::StoreOp:
|
||||
return AML::Store::parse(context);
|
||||
case AML::Byte::DerefOfOp:
|
||||
case AML::Byte::RefOfOp:
|
||||
return AML::Reference::parse(context);
|
||||
case AML::Byte::IndexOp:
|
||||
return AML::Index::parse(context);
|
||||
case AML::Byte::ReturnOp:
|
||||
{
|
||||
context.aml_data = context.aml_data.slice(1);
|
||||
|
|
Loading…
Reference in New Issue