From afb1d7ef0c4fe8b5b5a0e23998b6e57868954bbc Mon Sep 17 00:00:00 2001 From: Bananymous Date: Fri, 12 Apr 2024 01:47:40 +0300 Subject: [PATCH] Kernel: Implement more features for AML parser/interpreter Added - BankField - BufferField - PowerResource - ThermalZone - Reference - Package element forward declare --- kernel/include/kernel/ACPI/AML/Buffer.h | 153 ++++++++++++++++- kernel/include/kernel/ACPI/AML/Field.h | 36 ++++ kernel/include/kernel/ACPI/AML/Index.h | 96 +++++++++++ kernel/include/kernel/ACPI/AML/Integer.h | 9 +- kernel/include/kernel/ACPI/AML/Names.h | 17 ++ kernel/include/kernel/ACPI/AML/Node.h | 11 +- kernel/include/kernel/ACPI/AML/Package.h | 66 ++++++-- .../include/kernel/ACPI/AML/PowerResource.h | 68 ++++++++ kernel/include/kernel/ACPI/AML/Processor.h | 36 ++-- kernel/include/kernel/ACPI/AML/Reference.h | 155 ++++++++++++++++++ kernel/include/kernel/ACPI/AML/ThermalZone.h | 53 ++++++ kernel/kernel/ACPI/AML/Field.cpp | 96 +++++++++++ kernel/kernel/ACPI/AML/NamedObject.cpp | 8 +- kernel/kernel/ACPI/AML/Node.cpp | 25 ++- 14 files changed, 782 insertions(+), 47 deletions(-) create mode 100644 kernel/include/kernel/ACPI/AML/Index.h create mode 100644 kernel/include/kernel/ACPI/AML/PowerResource.h create mode 100644 kernel/include/kernel/ACPI/AML/Reference.h create mode 100644 kernel/include/kernel/ACPI/AML/ThermalZone.h diff --git a/kernel/include/kernel/ACPI/AML/Buffer.h b/kernel/include/kernel/ACPI/AML/Buffer.h index 9f8858ae5d..73a2562840 100644 --- a/kernel/include/kernel/ACPI/AML/Buffer.h +++ b/kernel/include/kernel/ACPI/AML/Buffer.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include #include @@ -12,7 +13,14 @@ namespace Kernel::ACPI::AML { BAN::Vector buffer; - Buffer() : AML::Node(Node::Type::Buffer) {} + Buffer() + : AML::Node(Node::Type::Buffer) + {} + + BAN::RefPtr 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; + size_t field_bit_offset; + size_t field_bit_size; + + BufferField(AML::NameSeg name, BAN::RefPtr 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 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::create(value)); + } + + bool store(BAN::RefPtr 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(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_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(); + 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::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(" }"); + } + + }; + } diff --git a/kernel/include/kernel/ACPI/AML/Field.h b/kernel/include/kernel/ACPI/AML/Field.h index abcb6743f5..d921b98c15 100644 --- a/kernel/include/kernel/ACPI/AML/Field.h +++ b/kernel/include/kernel/ACPI/AML/Field.h @@ -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 op_region; + BAN::RefPtr 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); + }; + } diff --git a/kernel/include/kernel/ACPI/AML/Index.h b/kernel/include/kernel/ACPI/AML/Index.h new file mode 100644 index 0000000000..3c785004c6 --- /dev/null +++ b/kernel/include/kernel/ACPI/AML/Index.h @@ -0,0 +1,96 @@ +#pragma once + +#include +#include +#include +#include + +namespace Kernel::ACPI::AML +{ + + struct Index + { + static ParseResult parse(ParseContext& context) + { + ASSERT(context.aml_data.size() >= 1); + ASSERT(static_cast(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(); + 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(); + if (!index.has_value()) + { + AML_ERROR("IndexOp index is not an integer"); + return ParseResult::Failure; + } + + BAN::RefPtr result; + switch (source->type) + { + case AML::Node::Type::Buffer: + { + auto buffer = static_cast(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::create(NameSeg(""sv), buffer, index.value() * 8, 8)); + result = MUST(BAN::RefPtr::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); + } + }; + +} diff --git a/kernel/include/kernel/ACPI/AML/Integer.h b/kernel/include/kernel/ACPI/AML/Integer.h index 6f66472a10..9ec5f6dbba 100644 --- a/kernel/include/kernel/ACPI/AML/Integer.h +++ b/kernel/include/kernel/ACPI/AML/Integer.h @@ -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 evaluate() override { - return MUST(BAN::RefPtr::create(value)); + return this; } static ParseResult parse(BAN::ConstByteSpan& aml_data) diff --git a/kernel/include/kernel/ACPI/AML/Names.h b/kernel/include/kernel/ACPI/AML/Names.h index 64719e78f8..98cbda0066 100644 --- a/kernel/include/kernel/ACPI/AML/Names.h +++ b/kernel/include/kernel/ACPI/AML/Names.h @@ -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_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 parse(BAN::ConstByteSpan& aml_data) { if (aml_data.size() == 0) diff --git a/kernel/include/kernel/ACPI/AML/Node.h b/kernel/include/kernel/ACPI/AML/Node.h index bffa04a812..1a6bfc5733 100644 --- a/kernel/include/kernel/ACPI/AML/Node.h +++ b/kernel/include/kernel/ACPI/AML/Node.h @@ -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 as_integer(); - virtual BAN::RefPtr evaluate() { AML_TODO("evaluate, type {}", static_cast(type)); return nullptr; } - virtual bool store(BAN::RefPtr source) { AML_TODO("store, type {}", static_cast(type)); return false; } + [[nodiscard]] BAN::Optional as_integer(); + [[nodiscard]] virtual BAN::RefPtr evaluate() { AML_TODO("evaluate, type {}", static_cast(type)); return nullptr; } + [[nodiscard]] virtual bool store(BAN::RefPtr source) { AML_TODO("store, type {}", static_cast(type)); return false; } virtual void debug_print(int indent) const = 0; }; diff --git a/kernel/include/kernel/ACPI/AML/Package.h b/kernel/include/kernel/ACPI/AML/Package.h index 6a10f57776..025450dcf4 100644 --- a/kernel/include/kernel/ACPI/AML/Package.h +++ b/kernel/include/kernel/ACPI/AML/Package.h @@ -10,27 +10,40 @@ namespace Kernel::ACPI::AML 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; - Package() : Node(Node::Type::Package) {} + Package(BAN::Vector>&& elements, BAN::Vector&& unresolved_references, AML::NameString scope) + : Node(Node::Type::Package) + , elements(BAN::move(elements)) + , unresolved_references(BAN::move(unresolved_references)) + , scope(scope) + {} BAN::RefPtr evaluate() override { - BAN::Vector> 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::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> elements; + BAN::Vector 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 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())); - auto package = MUST(BAN::RefPtr::create()); - package->elements = BAN::move(elements); + auto package = MUST(BAN::RefPtr::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); diff --git a/kernel/include/kernel/ACPI/AML/PowerResource.h b/kernel/include/kernel/ACPI/AML/PowerResource.h new file mode 100644 index 0000000000..a96892fb3e --- /dev/null +++ b/kernel/include/kernel/ACPI/AML/PowerResource.h @@ -0,0 +1,68 @@ +#pragma once + +#include +#include +#include +#include +#include + +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(context.aml_data[0]) == AML::Byte::ExtOpPrefix); + ASSERT(static_cast(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(*reinterpret_cast(power_res_pkg.data())); + power_res_pkg = power_res_pkg.slice(2); + + auto power_res = MUST(BAN::RefPtr::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); + } + }; + +} diff --git a/kernel/include/kernel/ACPI/AML/Processor.h b/kernel/include/kernel/ACPI/AML/Processor.h index d18e133398..0fff2b34e1 100644 --- a/kernel/include/kernel/ACPI/AML/Processor.h +++ b/kernel/include/kernel/ACPI/AML/Processor.h @@ -29,42 +29,46 @@ namespace Kernel::ACPI::AML ASSERT(static_cast(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(*reinterpret_cast(processor_pkg->data())); - processor_pkg = processor_pkg->slice(4); + uint32_t pblk_addr = BAN::little_endian_to_host(*reinterpret_cast(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::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); } }; diff --git a/kernel/include/kernel/ACPI/AML/Reference.h b/kernel/include/kernel/ACPI/AML/Reference.h new file mode 100644 index 0000000000..b068543cdc --- /dev/null +++ b/kernel/include/kernel/ACPI/AML/Reference.h @@ -0,0 +1,155 @@ +#pragma once + +#include +#include +#include +#include +#include +#include + +namespace Kernel::ACPI::AML +{ + + struct Reference : public AML::Node + { + BAN::RefPtr node; + + Reference(BAN::RefPtr node) + : Node(AML::Node::Type::Reference) + , node(node) + { + ASSERT(node); + } + + BAN::RefPtr evaluate() override + { + return this; + } + + static ParseResult parse(ParseContext& context) + { + ASSERT(context.aml_data.size() >= 1); + + bool conditional = false; + switch (static_cast(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(context.aml_data[1]) == AML::ExtOp::CondRefOfOp); + context.aml_data = context.aml_data.slice(2); + conditional = true; + break; + default: + ASSERT_NOT_REACHED(); + } + + BAN::RefPtr 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::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::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::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(context.aml_data[0]) == Byte::DerefOfOp); + context.aml_data = context.aml_data.slice(1); + + if (context.aml_data.size() >= 1 && static_cast(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(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(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(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("}"); + } + }; + +} diff --git a/kernel/include/kernel/ACPI/AML/ThermalZone.h b/kernel/include/kernel/ACPI/AML/ThermalZone.h new file mode 100644 index 0000000000..5c707c2a22 --- /dev/null +++ b/kernel/include/kernel/ACPI/AML/ThermalZone.h @@ -0,0 +1,53 @@ +#pragma once + +#include +#include +#include +#include +#include + +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(context.aml_data[0]) == AML::Byte::ExtOpPrefix); + ASSERT(static_cast(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::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); + } + }; + +} diff --git a/kernel/kernel/ACPI/AML/Field.cpp b/kernel/kernel/ACPI/AML/Field.cpp index 5c17331455..c64ffc4edc 100644 --- a/kernel/kernel/ACPI/AML/Field.cpp +++ b/kernel/kernel/ACPI/AML/Field.cpp @@ -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(context.aml_data[0]) == AML::Byte::ExtOpPrefix); + ASSERT(static_cast(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(); + 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 field_context; + field_context.field_rules.access_type = static_cast(field_flags & 0x0F); + field_context.field_rules.lock_rule = static_cast((field_flags >> 4) & 0x01); + field_context.field_rules.update_rule = static_cast((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(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 + ); + } + } diff --git a/kernel/kernel/ACPI/AML/NamedObject.cpp b/kernel/kernel/ACPI/AML/NamedObject.cpp index 28bc600cfc..72b0c1be33 100644 --- a/kernel/kernel/ACPI/AML/NamedObject.cpp +++ b/kernel/kernel/ACPI/AML/NamedObject.cpp @@ -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("}"); } diff --git a/kernel/kernel/ACPI/AML/Node.cpp b/kernel/kernel/ACPI/AML/Node.cpp index 5dbe97c9af..b5677b9242 100644 --- a/kernel/kernel/ACPI/AML/Node.cpp +++ b/kernel/kernel/ACPI/AML/Node.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -11,10 +12,13 @@ #include #include #include +#include #include +#include #include #include #include +#include #include namespace Kernel::ACPI @@ -31,7 +35,7 @@ namespace Kernel::ACPI if (!evaluated) return {}; if (evaluated->type == Type::Integer) - return static_cast(this)->value; + return static_cast(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);