From 53c356a940c78a3619cc1ed7e7684033f675792f Mon Sep 17 00:00:00 2001 From: Bananymous Date: Wed, 18 Dec 2024 19:26:19 +0200 Subject: [PATCH] Kernel: Implement AML MatchOp --- kernel/kernel/ACPI/AML/Node.cpp | 77 +++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) diff --git a/kernel/kernel/ACPI/AML/Node.cpp b/kernel/kernel/ACPI/AML/Node.cpp index 437c388d..5fcab425 100644 --- a/kernel/kernel/ACPI/AML/Node.cpp +++ b/kernel/kernel/ACPI/AML/Node.cpp @@ -1020,6 +1020,81 @@ namespace Kernel::ACPI::AML return result; } + static bool match_compare(const Package::Element& element, uint8_t opcode, uint64_t target) + { + if (!element.resolved || element.value.node == nullptr) + return false; + + auto element_copy = element.value.node->copy(); + if (element_copy.is_error()) + return false; + + auto element_conv = convert_node(element_copy.release_value(), ConvInteger, sizeof(uint64_t)); + if (element_conv.is_error()) + return false; + + switch (opcode) + { + case 0: return true; + case 1: return element_conv.value().as.integer.value == target; + case 2: return element_conv.value().as.integer.value <= target; + case 3: return element_conv.value().as.integer.value < target; + case 4: return element_conv.value().as.integer.value >= target; + case 5: return element_conv.value().as.integer.value > target; + } + + return false; + } + + static BAN::ErrorOr parse_match_op(ParseContext& context) + { + dprintln_if(AML_DUMP_FUNCTION_CALLS, "parse_match_op"); + + ASSERT(!context.aml_data.empty()); + ASSERT(static_cast(context.aml_data[0]) == AML::Byte::MatchOp); + context.aml_data = context.aml_data.slice(1); + + auto search = TRY(parse_node(context)); + if (search.type != Node::Type::Package) + { + dwarnln("Match search package is {}", search); + return BAN::Error::from_errno(EINVAL); + } + + if (context.aml_data.empty()) + return BAN::Error::from_errno(ENODATA); + const uint8_t opcode1 = context.aml_data[0]; + const uint64_t operand1 = TRY(convert_node(TRY(parse_node(context)), ConvInteger, sizeof(uint64_t))).as.integer.value; + + if (context.aml_data.empty()) + return BAN::Error::from_errno(ENODATA); + const uint8_t opcode2 = context.aml_data[0]; + const uint64_t operand2 = TRY(convert_node(TRY(parse_node(context)), ConvInteger, sizeof(uint64_t))).as.integer.value; + + const uint64_t start_idx = TRY(convert_node(TRY(parse_node(context)), ConvInteger, sizeof(uint64_t))).as.integer.value; + + Node result; + result.type = Node::Type::Integer; + result.as.integer.value = ONES; + + for (uint64_t i = start_idx; i < search.as.package->num_elements; i++) + { + auto& element = search.as.package->elements[i]; + if (!element.resolved) + TRY(resolve_package_element(element, false)); + + if (!match_compare(element, opcode1, operand1)) + continue; + if (!match_compare(element, opcode2, operand2)) + continue; + + result.as.integer.value = i; + break; + } + + return result; + } + static BAN::ErrorOr sizeof_impl(const Node& node) { Node result {}; @@ -2661,6 +2736,8 @@ namespace Kernel::ACPI::AML return TRY(parse_index_op(context)); case AML::Byte::ObjectTypeOp: return TRY(parse_object_type_op(context)); + case AML::Byte::MatchOp: + return TRY(parse_match_op(context)); case AML::Byte::ToBufferOp: case AML::Byte::ToDecimalStringOp: case AML::Byte::ToHexStringOp: