diff --git a/kernel/include/kernel/ACPI/AML.h b/kernel/include/kernel/ACPI/AML.h index 5f0185ce..61e6c44c 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 d036c15f..f1a033db 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 00000000..eaae2aad --- /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 6f1fbd97..ba78731f 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 00000000..184f0cb1 --- /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 76659b25..6f66472a 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 163b6683..4bb56562 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 a29fcf8a..e228d195 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 5ec80c92..817ca152 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 592644f7..c46a0840 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 e04a3bc0..bffa04a8 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 38d45492..1c74e9b8 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 55e294b9..d18e1333 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 f589a26e..44c310d2 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 00000000..9c89afe2 --- /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 00000000..886940d9 --- /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 355c9e7a..56289510 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 a70d4736..73c66b4f 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 58aef111..9bce4fb8 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 8708c6d2..28bc600c 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 a8fc8700..86849ba1 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 b0f7b23a..f3c79564 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 41997cb9..3aa1846b 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; }