Kernel: Implement more features for AML parser/interpreter

Added
   - BankField
   - BufferField
   - PowerResource
   - ThermalZone
   - Reference
   - Package element forward declare
This commit is contained in:
Bananymous 2024-04-12 01:47:40 +03:00
parent 93ddee5956
commit afb1d7ef0c
14 changed files with 782 additions and 47 deletions

View File

@ -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(" }");
}
};
}

View File

@ -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);
};
}

View File

@ -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);
}
};
}

View File

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

View File

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

View File

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

View File

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

View File

@ -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);
}
};
}

View File

@ -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);
}
};

View File

@ -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("}");
}
};
}

View File

@ -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);
}
};
}

View File

@ -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
);
}
}

View File

@ -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("}");
}

View File

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