From ff203d8d34dc5597c262042b4399837bb7736b3d Mon Sep 17 00:00:00 2001 From: Bananymous Date: Wed, 10 Apr 2024 01:52:14 +0300 Subject: [PATCH] Kernel: Implement more AML method invocation stuff Method invocation is starting to come together. This implemenetation can interpret some of the qemu's functions to enter ACPI mode. PCI config space access is currently the one thing is between entering ACPI mode. --- kernel/include/kernel/ACPI/AML.h | 13 +- kernel/include/kernel/ACPI/AML/Device.h | 26 ++- kernel/include/kernel/ACPI/AML/Expression.h | 162 ++++++++++++++++++ kernel/include/kernel/ACPI/AML/Field.h | 8 +- kernel/include/kernel/ACPI/AML/IfElse.h | 72 ++++++++ kernel/include/kernel/ACPI/AML/Integer.h | 4 +- kernel/include/kernel/ACPI/AML/Method.h | 29 ++-- kernel/include/kernel/ACPI/AML/Mutex.h | 2 +- kernel/include/kernel/ACPI/AML/NamedObject.h | 1 + kernel/include/kernel/ACPI/AML/Namespace.h | 2 + kernel/include/kernel/ACPI/AML/Node.h | 24 ++- kernel/include/kernel/ACPI/AML/ParseContext.h | 6 +- kernel/include/kernel/ACPI/AML/Processor.h | 2 +- kernel/include/kernel/ACPI/AML/Region.h | 19 +- kernel/include/kernel/ACPI/AML/Register.h | 53 ++++++ kernel/include/kernel/ACPI/AML/Store.h | 43 +++++ kernel/kernel/ACPI/ACPI.cpp | 2 +- kernel/kernel/ACPI/AML.cpp | 5 +- kernel/kernel/ACPI/AML/Field.cpp | 77 ++++++++- kernel/kernel/ACPI/AML/NamedObject.cpp | 2 +- kernel/kernel/ACPI/AML/Namespace.cpp | 59 +++---- kernel/kernel/ACPI/AML/Node.cpp | 101 ++++++++++- kernel/kernel/ACPI/AML/Scope.cpp | 15 +- 23 files changed, 619 insertions(+), 108 deletions(-) create mode 100644 kernel/include/kernel/ACPI/AML/Expression.h create mode 100644 kernel/include/kernel/ACPI/AML/IfElse.h create mode 100644 kernel/include/kernel/ACPI/AML/Register.h create mode 100644 kernel/include/kernel/ACPI/AML/Store.h diff --git a/kernel/include/kernel/ACPI/AML.h b/kernel/include/kernel/ACPI/AML.h index 5f0185ce3..61e6c44c5 100644 --- a/kernel/include/kernel/ACPI/AML.h +++ b/kernel/include/kernel/ACPI/AML.h @@ -3,18 +3,9 @@ #include #include -namespace Kernel::ACPI +namespace Kernel::ACPI::AML { - class AMLParser - { - public: - ~AMLParser(); - - static BAN::RefPtr parse_table(const SDTHeader& header); - - private: - AMLParser(); - }; + BAN::RefPtr initialize_namespace(const SDTHeader& header); } diff --git a/kernel/include/kernel/ACPI/AML/Device.h b/kernel/include/kernel/ACPI/AML/Device.h index d036c15fd..f1a033dbc 100644 --- a/kernel/include/kernel/ACPI/AML/Device.h +++ b/kernel/include/kernel/ACPI/AML/Device.h @@ -30,22 +30,27 @@ namespace Kernel::ACPI::AML return ParseResult::Failure; auto device = MUST(BAN::RefPtr::create(name_string->path.back())); - if (!context.root_namespace->add_named_object(context, name_string.value(), device)) + if (!Namespace::root_namespace()->add_named_object(context, name_string.value(), device)) return ParseResult::Failure; return device->enter_context_and_parse_term_list(context, name_string.value(), device_pkg.value()); } - void initialize(BAN::RefPtr root_namespace) + void initialize() { bool run_ini = true; bool init_children = true; - auto _sta = root_namespace->find_object(scope, NameString("_STA"sv)); + auto _sta = Namespace::root_namespace()->find_object(scope, NameString("_STA"sv)); if (_sta && _sta->type == Node::Type::Method) { auto* method = static_cast(_sta.ptr()); - auto result = method->evaluate(root_namespace); + if (method->arg_count != 0) + { + AML_ERROR("Method {}._STA has {} arguments, expected 0", scope, method->arg_count); + return; + } + auto result = method->evaluate({}); if (!result.has_value()) { AML_ERROR("Failed to evaluate {}._STA", scope); @@ -60,6 +65,8 @@ namespace Kernel::ACPI::AML if (!result_val.has_value()) { AML_ERROR("Failed to evaluate {}._STA, return value could not be resolved to integer", scope); + AML_ERROR(" Return value: "); + result.value()->debug_print(0); return; } run_ini = (result_val.value() & 0x01); @@ -68,11 +75,16 @@ namespace Kernel::ACPI::AML if (run_ini) { - auto _ini = root_namespace->find_object(scope, NameString("_INI"sv)); + auto _ini = Namespace::root_namespace()->find_object(scope, NameString("_INI"sv)); if (_ini && _ini->type == Node::Type::Method) { auto* method = static_cast(_ini.ptr()); - method->evaluate(root_namespace); + if (method->arg_count != 0) + { + AML_ERROR("Method {}._INI has {} arguments, expected 0", scope, method->arg_count); + return; + } + method->evaluate({}); } } @@ -83,7 +95,7 @@ namespace Kernel::ACPI::AML if (child->type == Node::Type::Device) { auto* device = static_cast(child.ptr()); - device->initialize(root_namespace); + device->initialize(); } } } diff --git a/kernel/include/kernel/ACPI/AML/Expression.h b/kernel/include/kernel/ACPI/AML/Expression.h new file mode 100644 index 000000000..eaae2aad5 --- /dev/null +++ b/kernel/include/kernel/ACPI/AML/Expression.h @@ -0,0 +1,162 @@ +#pragma once + +#include +#include +#include +#include + +namespace Kernel::ACPI::AML +{ + + struct Expression + { + static ParseResult parse(ParseContext& context) + { + ASSERT(context.aml_data.size() >= 1); + switch (static_cast(context.aml_data[0])) + { + // unary + case AML::Byte::IncrementOp: + case AML::Byte::DecrementOp: + case AML::Byte::NotOp: + case AML::Byte::LNotOp: + AML_TODO("Expression {2H}", context.aml_data[0]); + return ParseResult::Failure; + // binary + case AML::Byte::AddOp: + case AML::Byte::AndOp: + case AML::Byte::ModOp: + case AML::Byte::MultiplyOp: + case AML::Byte::NandOp: + case AML::Byte::NorOp: + case AML::Byte::OrOp: + case AML::Byte::ShiftLeftOp: + case AML::Byte::ShiftRightOp: + case AML::Byte::SubtractOp: + case AML::Byte::XorOp: + case AML::Byte::LAndOp: + case AML::Byte::LEqualOp: + case AML::Byte::LGreaterOp: + case AML::Byte::LLessOp: + case AML::Byte::LOrOp: + { + auto opcode = static_cast(context.aml_data[0]); + context.aml_data = context.aml_data.slice(1); + + auto lhs_result = AML::parse_object(context); + if (!lhs_result.success()) + return ParseResult::Failure; + auto lhs_node = lhs_result.node(); + if (!lhs_node) + { + AML_ERROR("LHS object is null"); + return ParseResult::Failure; + } + auto lhs = lhs_node->evaluate(); + if (!lhs) + { + AML_ERROR("Failed to evaluate LHS object"); + return ParseResult::Failure; + } + + auto rhs_result = AML::parse_object(context); + if (!rhs_result.success()) + return ParseResult::Failure; + auto rhs_node = rhs_result.node(); + if (!rhs_node) + { + AML_ERROR("RHS object is null"); + return ParseResult::Failure; + } + auto rhs = rhs_node->evaluate(); + if (!rhs) + { + AML_ERROR("Failed to evaluate RHS object"); + return ParseResult::Failure; + } + + return parse_binary_op(context, opcode, lhs, rhs); + } + // trinary + case AML::Byte::DivideOp: + AML_TODO("Expression {2H}", context.aml_data[0]); + return ParseResult::Failure; + default: + ASSERT_NOT_REACHED(); + } + } + + private: + static ParseResult parse_binary_op(ParseContext& context, AML::Byte opcode, BAN::RefPtr lhs_node, BAN::RefPtr rhs_node) + { + if (lhs_node->type != AML::Node::Type::Integer) + { + AML_TODO("LHS object is not an integer, type {}", static_cast(lhs_node->type)); + return ParseResult::Failure; + } + if (rhs_node->type != AML::Node::Type::Integer) + { + AML_TODO("RHS object is not an integer, type {}", static_cast(rhs_node->type)); + return ParseResult::Failure; + } + + bool logical = false; + uint64_t (*func)(uint64_t, uint64_t) = nullptr; + switch (opcode) + { + case AML::Byte::AddOp: func = [](uint64_t a, uint64_t b) { return a + b; }; break; + case AML::Byte::AndOp: func = [](uint64_t a, uint64_t b) { return a & b; }; break; + case AML::Byte::ModOp: func = [](uint64_t a, uint64_t b) { return a % b; }; break; + case AML::Byte::MultiplyOp: func = [](uint64_t a, uint64_t b) { return a * b; }; break; + case AML::Byte::NandOp: func = [](uint64_t a, uint64_t b) { return ~(a & b); }; break; + case AML::Byte::NorOp: func = [](uint64_t a, uint64_t b) { return ~(a | b); }; break; + case AML::Byte::OrOp: func = [](uint64_t a, uint64_t b) { return a | b; }; break; + case AML::Byte::ShiftLeftOp: func = [](uint64_t a, uint64_t b) { return a << b; }; break; + case AML::Byte::ShiftRightOp: func = [](uint64_t a, uint64_t b) { return a >> b; }; break; + case AML::Byte::SubtractOp: func = [](uint64_t a, uint64_t b) { return a - b; }; break; + case AML::Byte::XorOp: func = [](uint64_t a, uint64_t b) { return a ^ b; }; break; + case AML::Byte::LAndOp: func = [](uint64_t a, uint64_t b) { return a && b ? Integer::Ones : 0; }; logical = true; break; + case AML::Byte::LEqualOp: func = [](uint64_t a, uint64_t b) { return a == b ? Integer::Ones : 0; }; logical = true; break; + case AML::Byte::LGreaterOp: func = [](uint64_t a, uint64_t b) { return a > b ? Integer::Ones : 0; }; logical = true; break; + case AML::Byte::LLessOp: func = [](uint64_t a, uint64_t b) { return a < b ? Integer::Ones : 0; }; logical = true; break; + case AML::Byte::LOrOp: func = [](uint64_t a, uint64_t b) { return a || b ? Integer::Ones : 0; }; logical = true; break; + default: + ASSERT_NOT_REACHED(); + } + + uint64_t lhs = static_cast(lhs_node.ptr())->value; + uint64_t rhs = static_cast(rhs_node.ptr())->value; + uint64_t result = func(lhs, rhs); + + auto result_node = MUST(BAN::RefPtr::create(result)); + + if (!logical) + { + 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 target_result = AML::parse_object(context); + if (!target_result.success()) + return ParseResult::Failure; + auto target = target_result.node(); + if (!target) + { + AML_ERROR("Target object is null"); + return ParseResult::Failure; + } + if (!target->store(result_node)) + { + AML_ERROR("Failed to store result"); + return ParseResult::Failure; + } + } + } + + return ParseResult(result_node); + } + }; + +} diff --git a/kernel/include/kernel/ACPI/AML/Field.h b/kernel/include/kernel/ACPI/AML/Field.h index 6f1fbd979..ba78731f9 100644 --- a/kernel/include/kernel/ACPI/AML/Field.h +++ b/kernel/include/kernel/ACPI/AML/Field.h @@ -44,7 +44,7 @@ namespace Kernel::ACPI::AML FieldRules access_rules; - OpRegion* op_region = nullptr; + BAN::RefPtr op_region = nullptr; FieldElement(NameSeg name, uint64_t bit_offset, uint32_t bit_count, FieldRules access_rules) : NamedObject(Node::Type::FieldElement, name) @@ -53,6 +53,8 @@ namespace Kernel::ACPI::AML , access_rules(access_rules) {} + BAN::RefPtr evaluate() override; + void debug_print(int indent) const override; }; @@ -68,8 +70,8 @@ namespace Kernel::ACPI::AML FieldRules access_rules; - FieldElement* index_element = nullptr; - FieldElement* data_element = nullptr; + BAN::RefPtr index_element = nullptr; + BAN::RefPtr data_element = nullptr; IndexFieldElement(NameSeg name, uint64_t bit_offset, uint32_t bit_count, FieldRules access_rules) : NamedObject(Node::Type::IndexFieldElement, name) diff --git a/kernel/include/kernel/ACPI/AML/IfElse.h b/kernel/include/kernel/ACPI/AML/IfElse.h new file mode 100644 index 000000000..184f0cb17 --- /dev/null +++ b/kernel/include/kernel/ACPI/AML/IfElse.h @@ -0,0 +1,72 @@ +#pragma once + +#include +#include +#include +#include + +namespace Kernel::ACPI::AML +{ + + struct IfElse + { + static ParseResult parse(ParseContext& context) + { + ASSERT(context.aml_data.size() >= 1); + ASSERT(static_cast(context.aml_data[0]) == Byte::IfOp); + context.aml_data = context.aml_data.slice(1); + + auto if_pkg = AML::parse_pkg(context.aml_data); + if (!if_pkg.has_value()) + return ParseResult::Failure; + + auto outer_aml_data = context.aml_data; + context.aml_data = if_pkg.value(); + + auto predicate = AML::parse_object(context); + if (!predicate.success()) + return ParseResult::Failure; + auto predicate_node = predicate.node(); + if (!predicate_node) + { + AML_ERROR("If predicate is not an integer"); + return ParseResult::Failure; + } + auto predicate_integer = predicate_node->as_integer(); + if (!predicate_integer.has_value()) + { + AML_ERROR("If predicate is not an integer"); + return ParseResult::Failure; + } + + // Else + if (!predicate_integer.value()) + { + if (outer_aml_data.size() < 1 || static_cast(outer_aml_data[0]) != Byte::ElseOp) + context.aml_data = BAN::ConstByteSpan(); + else + { + outer_aml_data = outer_aml_data.slice(1); + auto else_pkg = AML::parse_pkg(outer_aml_data); + if (!else_pkg.has_value()) + return ParseResult::Failure; + context.aml_data = else_pkg.value(); + } + } + + while (context.aml_data.size() > 0) + { + auto object_result = AML::parse_object(context); + if (object_result.returned()) + return ParseResult(ParseResult::Result::Returned, object_result.node()); + if (!object_result.success()) + return ParseResult::Failure; + } + + context.aml_data = outer_aml_data; + + return ParseResult::Success; + } + }; + +} diff --git a/kernel/include/kernel/ACPI/AML/Integer.h b/kernel/include/kernel/ACPI/AML/Integer.h index 76659b25f..6f66472a1 100644 --- a/kernel/include/kernel/ACPI/AML/Integer.h +++ b/kernel/include/kernel/ACPI/AML/Integer.h @@ -18,9 +18,9 @@ namespace Kernel::ACPI::AML Integer(uint64_t value) : Node(Node::Type::Integer), value(value) {} - BAN::Optional as_integer() const override + BAN::RefPtr evaluate() override { - return value; + return MUST(BAN::RefPtr::create(value)); } static ParseResult parse(BAN::ConstByteSpan& aml_data) diff --git a/kernel/include/kernel/ACPI/AML/Method.h b/kernel/include/kernel/ACPI/AML/Method.h index 163b66838..4bb565629 100644 --- a/kernel/include/kernel/ACPI/AML/Method.h +++ b/kernel/include/kernel/ACPI/AML/Method.h @@ -11,6 +11,8 @@ namespace Kernel::ACPI::AML struct Method : public AML::Scope { + using Arguments = BAN::Array, 7>; + uint8_t arg_count; bool serialized; uint8_t sync_level; @@ -49,10 +51,10 @@ namespace Kernel::ACPI::AML (method_flags >> 3) & 0x01, method_flags >> 4 )); - if (!context.root_namespace->add_named_object(context, name_string.value(), method)) + if (!Namespace::root_namespace()->add_named_object(context, name_string.value(), method)) return ParseResult::Failure; - auto method_scope = context.root_namespace->resolve_path(context.scope, name_string.value()); + auto method_scope = Namespace::root_namespace()->resolve_path(context.scope, name_string.value()); if (!method_scope.has_value()) return ParseResult::Failure; method->term_list = method_pkg.value(); @@ -66,37 +68,32 @@ namespace Kernel::ACPI::AML return ParseResult::Success; } - BAN::Optional> evaluate(BAN::RefPtr root_namespace) + BAN::Optional> evaluate(Arguments args) { ParseContext context; - context.root_namespace = root_namespace.ptr(); context.aml_data = term_list; context.scope = scope; - - AML_DEBUG_PRINTLN("Evaluating method {}", scope); + context.method_args = args; + for (auto& local : context.method_locals) + local = MUST(BAN::RefPtr::create()); BAN::Optional> return_value; - ASSERT(arg_count == 0); while (context.aml_data.size() > 0) { - if (static_cast(context.aml_data[0]) == AML::Byte::ReturnOp) + auto parse_result = AML::parse_object(context); + if (parse_result.returned()) { - context.aml_data = context.aml_data.slice(1); - auto result = AML::parse_object(context); - if (result.success()) - return_value = result.node(); + return_value = parse_result.node(); break; } - - auto object_result = AML::parse_object(context); - if (!object_result.success()) + if (!parse_result.success()) break; } while (!context.created_objects.empty()) { - root_namespace->remove_named_object(context.created_objects.back()); + Namespace::root_namespace()->remove_named_object(context.created_objects.back()); context.created_objects.pop_back(); } diff --git a/kernel/include/kernel/ACPI/AML/Mutex.h b/kernel/include/kernel/ACPI/AML/Mutex.h index a29fcf8ab..e228d195d 100644 --- a/kernel/include/kernel/ACPI/AML/Mutex.h +++ b/kernel/include/kernel/ACPI/AML/Mutex.h @@ -39,7 +39,7 @@ namespace Kernel::ACPI::AML } auto mutex = MUST(BAN::RefPtr::create(name->path.back(), sync_level)); - if (!context.root_namespace->add_named_object(context, name.value(), mutex)) + if (!Namespace::root_namespace()->add_named_object(context, name.value(), mutex)) return ParseResult::Failure; #if AML_DEBUG_LEVEL >= 2 diff --git a/kernel/include/kernel/ACPI/AML/NamedObject.h b/kernel/include/kernel/ACPI/AML/NamedObject.h index 5ec80c92c..817ca1520 100644 --- a/kernel/include/kernel/ACPI/AML/NamedObject.h +++ b/kernel/include/kernel/ACPI/AML/NamedObject.h @@ -8,6 +8,7 @@ namespace Kernel::ACPI::AML struct NamedObject : public Node { + BAN::RefPtr parent; NameSeg name; NamedObject(Node::Type type, NameSeg name) : Node(type), name(name) {} diff --git a/kernel/include/kernel/ACPI/AML/Namespace.h b/kernel/include/kernel/ACPI/AML/Namespace.h index 592644f77..c46a0840b 100644 --- a/kernel/include/kernel/ACPI/AML/Namespace.h +++ b/kernel/include/kernel/ACPI/AML/Namespace.h @@ -7,6 +7,8 @@ namespace Kernel::ACPI::AML struct Namespace : public AML::Scope { + static BAN::RefPtr root_namespace(); + Namespace(NameSeg name) : AML::Scope(Node::Type::Namespace, name) {} static BAN::RefPtr parse(BAN::ConstByteSpan aml); diff --git a/kernel/include/kernel/ACPI/AML/Node.h b/kernel/include/kernel/ACPI/AML/Node.h index e04a3bc00..bffa04a81 100644 --- a/kernel/include/kernel/ACPI/AML/Node.h +++ b/kernel/include/kernel/ACPI/AML/Node.h @@ -4,6 +4,7 @@ #include #include #include +#include namespace Kernel::ACPI::AML { @@ -24,6 +25,7 @@ namespace Kernel::ACPI::AML OpRegion, Package, Processor, + Register, String, }; const Type type; @@ -32,7 +34,10 @@ namespace Kernel::ACPI::AML virtual ~Node() = default; virtual bool is_scope() const { return false; } - virtual BAN::Optional as_integer() const { return {}; } + + 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; } virtual void debug_print(int indent) const = 0; }; @@ -47,12 +52,25 @@ namespace Kernel::ACPI::AML { Success, Failure, + Returned, }; - ParseResult(Result success) : m_result(success) {} - ParseResult(BAN::RefPtr node) : m_result(Result::Success), m_node(BAN::move(node)) { ASSERT(m_node); } + ParseResult(Result success) + : m_result(success) + {} + ParseResult(Result success, BAN::RefPtr node) + : m_result(success) + , m_node(BAN::move(node)) + {} + ParseResult(BAN::RefPtr node) + : m_result(Result::Success) + , m_node(BAN::move(node)) + { + ASSERT(m_node); + } bool success() const { return m_result == Result::Success; } + bool returned() const { return m_result == Result::Returned; } BAN::RefPtr node() { diff --git a/kernel/include/kernel/ACPI/AML/ParseContext.h b/kernel/include/kernel/ACPI/AML/ParseContext.h index 38d45492f..1c74e9b84 100644 --- a/kernel/include/kernel/ACPI/AML/ParseContext.h +++ b/kernel/include/kernel/ACPI/AML/ParseContext.h @@ -1,9 +1,11 @@ #pragma once +#include #include #include #include #include +#include namespace Kernel::ACPI::AML { @@ -12,12 +14,14 @@ namespace Kernel::ACPI::AML { BAN::ConstByteSpan aml_data; AML::NameString scope; - AML::Namespace* root_namespace; // Used for cleaning up on method exit // NOTE: This uses linked list instead of vector because // we don't really need large contiguous memory BAN::LinkedList created_objects; + + BAN::Array, 7> method_args; + BAN::Array, 8> method_locals; }; } diff --git a/kernel/include/kernel/ACPI/AML/Processor.h b/kernel/include/kernel/ACPI/AML/Processor.h index 55e294b9d..d18e13339 100644 --- a/kernel/include/kernel/ACPI/AML/Processor.h +++ b/kernel/include/kernel/ACPI/AML/Processor.h @@ -53,7 +53,7 @@ namespace Kernel::ACPI::AML processor_pkg = processor_pkg->slice(1); auto processor = MUST(BAN::RefPtr::create(name->path.back(), id, pblk_addr, pblk_len)); - if (!context.root_namespace->add_named_object(context, name.value(), processor)) + 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()); diff --git a/kernel/include/kernel/ACPI/AML/Region.h b/kernel/include/kernel/ACPI/AML/Region.h index f589a26e6..44c310d28 100644 --- a/kernel/include/kernel/ACPI/AML/Region.h +++ b/kernel/include/kernel/ACPI/AML/Region.h @@ -23,12 +23,15 @@ namespace Kernel::ACPI::AML GenericSerialBus = 9, PCC = 10, }; - RegionSpace space; - uint64_t offset; - uint64_t length; + RegionSpace region_space; + uint64_t region_offset; + uint64_t region_length; - OpRegion(NameSeg name, RegionSpace space, uint64_t offset, uint64_t length) - : NamedObject(Node::Type::OpRegion, name), space(space), offset(offset), length(length) + OpRegion(NameSeg name, RegionSpace region_space, uint64_t region_offset, uint64_t region_length) + : NamedObject(Node::Type::OpRegion, name) + , region_space(region_space) + , region_offset(region_offset) + , region_length(region_length) {} static ParseResult parse(AML::ParseContext& context) @@ -74,7 +77,7 @@ namespace Kernel::ACPI::AML length.value() )); - if (!context.root_namespace->add_named_object(context, name.value(), op_region)) + if (!Namespace::root_namespace()->add_named_object(context, name.value(), op_region)) return ParseResult::Failure; #if AML_DEBUG_LEVEL >= 2 @@ -88,7 +91,7 @@ namespace Kernel::ACPI::AML virtual void debug_print(int indent) const override { BAN::StringView region_space_name; - switch (space) + switch (region_space) { case RegionSpace::SystemMemory: region_space_name = "SystemMemory"sv; break; case RegionSpace::SystemIO: region_space_name = "SystemIO"sv; break; @@ -106,7 +109,7 @@ namespace Kernel::ACPI::AML AML_DEBUG_PRINT_INDENT(indent); AML_DEBUG_PRINT("OperationRegion("); name.debug_print(); - AML_DEBUG_PRINT(", {}, 0x{H}, 0x{H})", region_space_name, offset, length); + AML_DEBUG_PRINT(", {}, 0x{H}, 0x{H})", region_space_name, region_offset, region_length); } }; diff --git a/kernel/include/kernel/ACPI/AML/Register.h b/kernel/include/kernel/ACPI/AML/Register.h new file mode 100644 index 000000000..9c89afe2e --- /dev/null +++ b/kernel/include/kernel/ACPI/AML/Register.h @@ -0,0 +1,53 @@ +#pragma once + +#include + +namespace Kernel::ACPI::AML +{ + + struct Register : public AML::Node + { + BAN::RefPtr value; + + Register() + : Node(Node::Type::Register) + {} + Register(BAN::RefPtr value) + : Node(Node::Type::Register) + , value(value) + {} + + BAN::RefPtr evaluate() override + { + if (value) + return value->evaluate(); + return {}; + } + + bool store(BAN::RefPtr source) override + { + auto evaluated = source->evaluate(); + if (!evaluated) + { + AML_ERROR("Failed to evaluate source for store"); + return false; + } + value = evaluated; + return true; + } + + void debug_print(int indent) const override + { + AML_DEBUG_PRINT_INDENT(indent); + AML_DEBUG_PRINT("Register\n"); + if (value) + value->debug_print(indent + 1); + else + { + AML_DEBUG_PRINT_INDENT(indent + 1); + AML_DEBUG_PRINT("No value\n"); + } + } + }; + +} diff --git a/kernel/include/kernel/ACPI/AML/Store.h b/kernel/include/kernel/ACPI/AML/Store.h new file mode 100644 index 000000000..886940d9e --- /dev/null +++ b/kernel/include/kernel/ACPI/AML/Store.h @@ -0,0 +1,43 @@ +#pragma once + +#include +#include + +namespace Kernel::ACPI::AML +{ + + struct Store + { + static ParseResult parse(ParseContext& context) + { + ASSERT(context.aml_data.size() >= 1); + ASSERT(static_cast(context.aml_data[0]) == Byte::StoreOp); + 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(); + if (!source) + { + AML_ERROR("Store source is null"); + return ParseResult::Failure; + } + + auto destination_result = AML::parse_object(context); + if (!destination_result.success()) + return ParseResult::Failure; + auto destination = destination_result.node(); + if (!destination) + { + AML_ERROR("Store destination is null"); + return ParseResult::Failure; + } + + if (!destination->store(source)) + return ParseResult::Failure; + return ParseResult::Success; + } + }; + +} diff --git a/kernel/kernel/ACPI/ACPI.cpp b/kernel/kernel/ACPI/ACPI.cpp index 355c9e7ac..562895104 100644 --- a/kernel/kernel/ACPI/ACPI.cpp +++ b/kernel/kernel/ACPI/ACPI.cpp @@ -35,7 +35,7 @@ namespace Kernel::ACPI auto dsdt = s_instance->get_header("DSDT", 0); ASSERT(dsdt); - s_instance->m_namespace = AMLParser::parse_table(*dsdt); + s_instance->m_namespace = AML::initialize_namespace(*dsdt); #if ARCH(x86_64) lai_create_namespace(); diff --git a/kernel/kernel/ACPI/AML.cpp b/kernel/kernel/ACPI/AML.cpp index a70d47366..73c66b4fb 100644 --- a/kernel/kernel/ACPI/AML.cpp +++ b/kernel/kernel/ACPI/AML.cpp @@ -6,10 +6,7 @@ namespace Kernel::ACPI { - AMLParser::AMLParser() = default; - AMLParser::~AMLParser() = default; - - BAN::RefPtr AMLParser::parse_table(const SDTHeader& header) + BAN::RefPtr AML::initialize_namespace(const SDTHeader& header) { dprintln("Parsing {}, {} bytes of AML", header, header.length); diff --git a/kernel/kernel/ACPI/AML/Field.cpp b/kernel/kernel/ACPI/AML/Field.cpp index 58aef1112..9bce4fb8e 100644 --- a/kernel/kernel/ACPI/AML/Field.cpp +++ b/kernel/kernel/ACPI/AML/Field.cpp @@ -1,4 +1,5 @@ #include +#include namespace Kernel::ACPI { @@ -93,7 +94,7 @@ namespace Kernel::ACPI if (!name_string.has_value()) return ParseResult::Failure; - auto op_region = context.root_namespace->find_object(context.scope, name_string.value()); + auto op_region = Namespace::root_namespace()->find_object(context.scope, name_string.value()); if (!op_region || op_region->type != AML::Node::Type::OpRegion) { AML_ERROR("FieldOp: {} does not name a valid OpRegion", name_string.value()); @@ -121,7 +122,7 @@ namespace Kernel::ACPI NameString element_name; MUST(element_name.path.push_back(element->name)); - if (!context.root_namespace->add_named_object(context, element_name, element)) + if (!Namespace::root_namespace()->add_named_object(context, element_name, element)) return ParseResult::Failure; #if AML_DEBUG_LEVEL >= 2 @@ -133,6 +134,72 @@ namespace Kernel::ACPI return ParseResult::Success; } + BAN::RefPtr AML::FieldElement::evaluate() + { + // Field LockRule only applies to modifying the field, not reading it + + uint32_t access_size = 0; + switch (access_rules.access_type) + { + case FieldRules::AccessType::Any: + case FieldRules::AccessType::Byte: + access_size = 1; + break; + case FieldRules::AccessType::Word: + access_size = 2; + break; + case FieldRules::AccessType::DWord: + access_size = 4; + break; + case FieldRules::AccessType::QWord: + access_size = 8; + break; + case FieldRules::AccessType::Buffer: + AML_TODO("FieldElement evaluate with access type Buffer"); + return {}; + } + + switch (op_region->region_space) + { + case OpRegion::RegionSpace::SystemMemory: + { + uint64_t byte_offset = op_region->region_offset + (bit_offset / 8); + if (auto rem = byte_offset % access_size) + byte_offset -= rem; + + if ((bit_offset % access_size) + bit_count > access_size * 8) + { + AML_ERROR("FieldElement evaluate over multiple access sizes"); + return {}; + } + + if (byte_offset + access_size > op_region->region_offset + op_region->region_length) + { + AML_ERROR("FieldElement evaluate out of bounds"); + return {}; + } + + uint64_t result = 0; + PageTable::with_fast_page(byte_offset & PAGE_ADDR_MASK, [&] { + switch (access_size) + { + case 1: result = PageTable::fast_page_as_sized ((byte_offset % PAGE_SIZE) / access_size); break; + case 2: result = PageTable::fast_page_as_sized((byte_offset % PAGE_SIZE) / access_size); break; + case 4: result = PageTable::fast_page_as_sized((byte_offset % PAGE_SIZE) / access_size); break; + case 8: result = PageTable::fast_page_as_sized((byte_offset % PAGE_SIZE) / access_size); break; + } + }); + + result >>= bit_offset % access_size; + result &= ((uint64_t)1 << bit_count) - 1; + return MUST(BAN::RefPtr::create(result)); + } + default: + AML_TODO("FieldElement evaluate with region space {}", static_cast(op_region->region_space)); + return {}; + } + } + void AML::FieldElement::debug_print(int indent) const { AML_DEBUG_PRINT_INDENT(indent); @@ -158,7 +225,7 @@ namespace Kernel::ACPI auto index_field_element_name = NameString::parse(field_pkg); if (!index_field_element_name.has_value()) return ParseResult::Failure; - auto index_field_element = context.root_namespace->find_object(context.scope, index_field_element_name.value()); + auto index_field_element = Namespace::root_namespace()->find_object(context.scope, index_field_element_name.value()); if (!index_field_element || index_field_element->type != AML::Node::Type::FieldElement) { AML_ERROR("IndexField IndexName does not name a valid FieldElement"); @@ -168,7 +235,7 @@ namespace Kernel::ACPI auto data_field_element_name = NameString::parse(field_pkg); if (!data_field_element_name.has_value()) return ParseResult::Failure; - auto data_field_element = context.root_namespace->find_object(context.scope, data_field_element_name.value()); + auto data_field_element = Namespace::root_namespace()->find_object(context.scope, data_field_element_name.value()); if (!data_field_element || data_field_element->type != AML::Node::Type::FieldElement) { AML_ERROR("IndexField DataName does not name a valid FieldElement"); @@ -197,7 +264,7 @@ namespace Kernel::ACPI NameString element_name; MUST(element_name.path.push_back(element->name)); - if (!context.root_namespace->add_named_object(context, element_name, element)) + if (!Namespace::root_namespace()->add_named_object(context, element_name, element)) return ParseResult::Failure; #if AML_DEBUG_LEVEL >= 2 diff --git a/kernel/kernel/ACPI/AML/NamedObject.cpp b/kernel/kernel/ACPI/AML/NamedObject.cpp index 8708c6d29..28bc600cf 100644 --- a/kernel/kernel/ACPI/AML/NamedObject.cpp +++ b/kernel/kernel/ACPI/AML/NamedObject.cpp @@ -19,7 +19,7 @@ namespace Kernel::ACPI return ParseResult::Failure; auto name = MUST(BAN::RefPtr::create(name_string.value().path.back(), object.node())); - if (!context.root_namespace->add_named_object(context, name_string.value(), name)) + if (!Namespace::root_namespace()->add_named_object(context, name_string.value(), name)) return ParseResult::Failure; #if AML_DEBUG_LEVEL >= 2 diff --git a/kernel/kernel/ACPI/AML/Namespace.cpp b/kernel/kernel/ACPI/AML/Namespace.cpp index a8fc87008..86849ba14 100644 --- a/kernel/kernel/ACPI/AML/Namespace.cpp +++ b/kernel/kernel/ACPI/AML/Namespace.cpp @@ -5,6 +5,14 @@ namespace Kernel::ACPI { + static BAN::RefPtr s_root_namespace; + + BAN::RefPtr AML::Namespace::root_namespace() + { + ASSERT(s_root_namespace); + return s_root_namespace; + } + BAN::Optional AML::Namespace::resolve_path(const AML::NameString& relative_base, const AML::NameString& relative_path) { // Base must be non-empty absolute path @@ -143,6 +151,8 @@ namespace Kernel::ACPI return false; } + object->parent = parent_scope; + MUST(parent_scope->objects.insert(object->name, object)); auto canonical_scope = resolve_path(parse_context.scope, object_path); @@ -159,66 +169,39 @@ namespace Kernel::ACPI bool AML::Namespace::remove_named_object(const AML::NameString& absolute_path) { - auto canonical_path = resolve_path({}, absolute_path); - if (!canonical_path.has_value()) + auto object = find_object({}, absolute_path); + if (!object) { - AML_ERROR("Failed to resolve path"); + AML_ERROR("Object {} not found", absolute_path); return false; } - if (canonical_path->path.empty()) + if (object.ptr() == this) { AML_ERROR("Trying to remove root object"); return false; } - BAN::RefPtr parent_object = this; + auto parent = object->parent; + ASSERT(parent->is_scope()); - for (size_t i = 0; i < canonical_path->path.size() - 1; i++) - { - if (!parent_object->is_scope()) - { - AML_ERROR("Parent object is not a scope"); - return false; - } - - auto* parent_scope = static_cast(parent_object.ptr()); - - auto it = parent_scope->objects.find(canonical_path->path[i]); - if (it == parent_scope->objects.end()) - { - AML_ERROR("Object not found"); - return false; - } - - parent_object = it->value; - ASSERT(parent_object); - } - - if (!parent_object->is_scope()) - { - AML_ERROR("Parent object is not a scope"); - return false; - } - - auto* parent_scope = static_cast(parent_object.ptr()); - parent_scope->objects.remove(canonical_path->path.back()); + auto* parent_scope = static_cast(parent.ptr()); + parent_scope->objects.remove(object->name); return true; } BAN::RefPtr AML::Namespace::parse(BAN::ConstByteSpan aml_data) { - auto result = MUST(BAN::RefPtr::create(NameSeg("\\"sv))); + s_root_namespace = MUST(BAN::RefPtr::create(NameSeg("\\"sv))); AML::ParseContext context; context.scope = AML::NameString("\\"sv); context.aml_data = aml_data; - context.root_namespace = result.ptr(); // Add predefined namespaces #define ADD_PREDEFIED_NAMESPACE(NAME) \ - ASSERT(result->add_named_object(context, AML::NameString("\\" NAME), MUST(BAN::RefPtr::create(NameSeg(NAME))))); + ASSERT(s_root_namespace->add_named_object(context, AML::NameString("\\" NAME), MUST(BAN::RefPtr::create(NameSeg(NAME))))); ADD_PREDEFIED_NAMESPACE("_GPE"sv); ADD_PREDEFIED_NAMESPACE("_PR"sv); ADD_PREDEFIED_NAMESPACE("_SB"sv); @@ -236,7 +219,7 @@ namespace Kernel::ACPI } } - return result; + return s_root_namespace; } } diff --git a/kernel/kernel/ACPI/AML/Node.cpp b/kernel/kernel/ACPI/AML/Node.cpp index b0f7b23a7..f3c795647 100644 --- a/kernel/kernel/ACPI/AML/Node.cpp +++ b/kernel/kernel/ACPI/AML/Node.cpp @@ -1,7 +1,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -11,6 +13,7 @@ #include #include #include +#include #include #include @@ -20,6 +23,18 @@ namespace Kernel::ACPI AML::ParseResult AML::ParseResult::Failure = AML::ParseResult(AML::ParseResult::Result::Failure); AML::ParseResult AML::ParseResult::Success = AML::ParseResult(AML::ParseResult::Result::Success); + BAN::Optional AML::Node::as_integer() + { + if (type == Type::Integer) + return static_cast(this)->value; + auto evaluated = evaluate(); + if (!evaluated) + return {}; + if (evaluated->type == Type::Integer) + return static_cast(this)->value; + return {}; + } + AML::ParseResult AML::parse_object(AML::ParseContext& context) { if (context.aml_data.size() < 1) @@ -64,6 +79,53 @@ namespace Kernel::ACPI return AML::Integer::parse(context.aml_data); case AML::Byte::StringPrefix: return AML::String::parse(context); + case AML::Byte::Arg0: + case AML::Byte::Arg1: + case AML::Byte::Arg2: + case AML::Byte::Arg3: + case AML::Byte::Arg4: + case AML::Byte::Arg5: + case AML::Byte::Arg6: + { + uint8_t index = context.aml_data[0] - static_cast(AML::Byte::Arg0); + context.aml_data = context.aml_data.slice(1); + return ParseResult(context.method_args[index]); + } + case AML::Byte::Local0: + case AML::Byte::Local1: + case AML::Byte::Local2: + case AML::Byte::Local3: + case AML::Byte::Local4: + case AML::Byte::Local5: + case AML::Byte::Local6: + case AML::Byte::Local7: + { + uint8_t index = context.aml_data[0] - static_cast(AML::Byte::Local0); + context.aml_data = context.aml_data.slice(1); + return ParseResult(context.method_locals[index]); + } + case AML::Byte::AddOp: + case AML::Byte::AndOp: + case AML::Byte::DecrementOp: + case AML::Byte::DivideOp: + case AML::Byte::IncrementOp: + case AML::Byte::LAndOp: + case AML::Byte::LEqualOp: + case AML::Byte::LGreaterOp: + case AML::Byte::LLessOp: + case AML::Byte::LNotOp: + case AML::Byte::LOrOp: + case AML::Byte::ModOp: + case AML::Byte::MultiplyOp: + case AML::Byte::NandOp: + case AML::Byte::NorOp: + case AML::Byte::NotOp: + case AML::Byte::OrOp: + case AML::Byte::ShiftLeftOp: + case AML::Byte::ShiftRightOp: + case AML::Byte::SubtractOp: + case AML::Byte::XorOp: + return AML::Expression::parse(context); case AML::Byte::NameOp: return AML::Name::parse(context); case AML::Byte::PackageOp: @@ -74,6 +136,19 @@ namespace Kernel::ACPI return AML::Buffer::parse(context); case AML::Byte::ScopeOp: return AML::Scope::parse(context); + case AML::Byte::IfOp: + return AML::IfElse::parse(context); + case AML::Byte::StoreOp: + return AML::Store::parse(context); + case AML::Byte::ReturnOp: + { + context.aml_data = context.aml_data.slice(1); + auto result = AML::parse_object(context); + if (result.success()) + return ParseResult(ParseResult::Result::Returned, result.node()); + AML_ERROR("Failed to parse return value for method {}", context.scope); + return ParseResult::Failure; + } default: break; } @@ -86,12 +161,36 @@ namespace Kernel::ACPI auto name_string = AML::NameString::parse(context.aml_data); if (!name_string.has_value()) return ParseResult::Failure; - auto aml_object = context.root_namespace->find_object(context.scope, name_string.value()); + auto aml_object = Namespace::root_namespace()->find_object(context.scope, name_string.value()); if (!aml_object) { AML_ERROR("NameString {} not found in namespace", name_string.value()); return ParseResult::Failure; } + if (aml_object->type == AML::Node::Type::Method) + { + auto* method = static_cast(aml_object.ptr()); + + Method::Arguments args; + for (uint8_t i = 0; i < method->arg_count; i++) + { + auto arg = AML::parse_object(context); + if (!arg.success()) + { + AML_ERROR("Failed to parse argument {} for method {}", i, name_string.value()); + return ParseResult::Failure; + } + args[i] = MUST(BAN::RefPtr::create(arg.node())); + } + + auto result = method->evaluate(args); + if (!result.has_value()) + { + AML_ERROR("Failed to evaluate {}", name_string.value()); + return ParseResult::Failure; + } + return ParseResult(result.value()); + } return ParseResult(aml_object); } diff --git a/kernel/kernel/ACPI/AML/Scope.cpp b/kernel/kernel/ACPI/AML/Scope.cpp index 41997cb95..3aa1846b7 100644 --- a/kernel/kernel/ACPI/AML/Scope.cpp +++ b/kernel/kernel/ACPI/AML/Scope.cpp @@ -20,7 +20,7 @@ namespace Kernel::ACPI if (!name_string.has_value()) return ParseResult::Failure; - auto named_object = context.root_namespace->find_object(context.scope, name_string.value()); + auto named_object = Namespace::root_namespace()->find_object(context.scope, name_string.value()); if (!named_object) { AML_ERROR("Scope name {} not found in namespace", name_string.value()); @@ -38,17 +38,22 @@ namespace Kernel::ACPI AML::ParseResult AML::Scope::enter_context_and_parse_term_list(ParseContext& outer_context, const AML::NameString& name_string, BAN::ConstByteSpan aml_data) { - auto scope = outer_context.root_namespace->resolve_path(outer_context.scope, name_string); - if (!scope.has_value()) + auto resolved_scope = Namespace::root_namespace()->resolve_path(outer_context.scope, name_string); + if (!resolved_scope.has_value()) return ParseResult::Failure; ParseContext scope_context; - scope_context.root_namespace = outer_context.root_namespace; - scope_context.scope = scope.release_value(); + scope_context.scope = resolved_scope.release_value(); scope_context.aml_data = aml_data; + scope_context.method_args = outer_context.method_args; while (scope_context.aml_data.size() > 0) { auto object_result = AML::parse_object(scope_context); + if (object_result.returned()) + { + AML_ERROR("Unexpected return from scope {}", scope_context.scope); + return ParseResult::Failure; + } if (!object_result.success()) return ParseResult::Failure; }