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.
This commit is contained in:
parent
23fa39121c
commit
ff203d8d34
|
@ -3,18 +3,9 @@
|
||||||
#include <kernel/ACPI/Headers.h>
|
#include <kernel/ACPI/Headers.h>
|
||||||
#include <kernel/ACPI/AML/Namespace.h>
|
#include <kernel/ACPI/AML/Namespace.h>
|
||||||
|
|
||||||
namespace Kernel::ACPI
|
namespace Kernel::ACPI::AML
|
||||||
{
|
{
|
||||||
|
|
||||||
class AMLParser
|
BAN::RefPtr<AML::Namespace> initialize_namespace(const SDTHeader& header);
|
||||||
{
|
|
||||||
public:
|
|
||||||
~AMLParser();
|
|
||||||
|
|
||||||
static BAN::RefPtr<AML::Namespace> parse_table(const SDTHeader& header);
|
|
||||||
|
|
||||||
private:
|
|
||||||
AMLParser();
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,22 +30,27 @@ namespace Kernel::ACPI::AML
|
||||||
return ParseResult::Failure;
|
return ParseResult::Failure;
|
||||||
|
|
||||||
auto device = MUST(BAN::RefPtr<Device>::create(name_string->path.back()));
|
auto device = MUST(BAN::RefPtr<Device>::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 ParseResult::Failure;
|
||||||
|
|
||||||
return device->enter_context_and_parse_term_list(context, name_string.value(), device_pkg.value());
|
return device->enter_context_and_parse_term_list(context, name_string.value(), device_pkg.value());
|
||||||
}
|
}
|
||||||
|
|
||||||
void initialize(BAN::RefPtr<AML::Namespace> root_namespace)
|
void initialize()
|
||||||
{
|
{
|
||||||
bool run_ini = true;
|
bool run_ini = true;
|
||||||
bool init_children = 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)
|
if (_sta && _sta->type == Node::Type::Method)
|
||||||
{
|
{
|
||||||
auto* method = static_cast<Method*>(_sta.ptr());
|
auto* method = static_cast<Method*>(_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())
|
if (!result.has_value())
|
||||||
{
|
{
|
||||||
AML_ERROR("Failed to evaluate {}._STA", scope);
|
AML_ERROR("Failed to evaluate {}._STA", scope);
|
||||||
|
@ -60,6 +65,8 @@ namespace Kernel::ACPI::AML
|
||||||
if (!result_val.has_value())
|
if (!result_val.has_value())
|
||||||
{
|
{
|
||||||
AML_ERROR("Failed to evaluate {}._STA, return value could not be resolved to integer", scope);
|
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;
|
return;
|
||||||
}
|
}
|
||||||
run_ini = (result_val.value() & 0x01);
|
run_ini = (result_val.value() & 0x01);
|
||||||
|
@ -68,11 +75,16 @@ namespace Kernel::ACPI::AML
|
||||||
|
|
||||||
if (run_ini)
|
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)
|
if (_ini && _ini->type == Node::Type::Method)
|
||||||
{
|
{
|
||||||
auto* method = static_cast<Method*>(_ini.ptr());
|
auto* method = static_cast<Method*>(_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)
|
if (child->type == Node::Type::Device)
|
||||||
{
|
{
|
||||||
auto* device = static_cast<Device*>(child.ptr());
|
auto* device = static_cast<Device*>(child.ptr());
|
||||||
device->initialize(root_namespace);
|
device->initialize();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,162 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <kernel/ACPI/AML/Bytes.h>
|
||||||
|
#include <kernel/ACPI/AML/Integer.h>
|
||||||
|
#include <kernel/ACPI/AML/Node.h>
|
||||||
|
#include <kernel/ACPI/AML/ParseContext.h>
|
||||||
|
|
||||||
|
namespace Kernel::ACPI::AML
|
||||||
|
{
|
||||||
|
|
||||||
|
struct Expression
|
||||||
|
{
|
||||||
|
static ParseResult parse(ParseContext& context)
|
||||||
|
{
|
||||||
|
ASSERT(context.aml_data.size() >= 1);
|
||||||
|
switch (static_cast<Byte>(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<AML::Byte>(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<AML::Node> lhs_node, BAN::RefPtr<AML::Node> rhs_node)
|
||||||
|
{
|
||||||
|
if (lhs_node->type != AML::Node::Type::Integer)
|
||||||
|
{
|
||||||
|
AML_TODO("LHS object is not an integer, type {}", static_cast<uint8_t>(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<uint8_t>(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<AML::Integer*>(lhs_node.ptr())->value;
|
||||||
|
uint64_t rhs = static_cast<AML::Integer*>(rhs_node.ptr())->value;
|
||||||
|
uint64_t result = func(lhs, rhs);
|
||||||
|
|
||||||
|
auto result_node = MUST(BAN::RefPtr<AML::Integer>::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);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -44,7 +44,7 @@ namespace Kernel::ACPI::AML
|
||||||
|
|
||||||
FieldRules access_rules;
|
FieldRules access_rules;
|
||||||
|
|
||||||
OpRegion* op_region = nullptr;
|
BAN::RefPtr<OpRegion> op_region = nullptr;
|
||||||
|
|
||||||
FieldElement(NameSeg name, uint64_t bit_offset, uint32_t bit_count, FieldRules access_rules)
|
FieldElement(NameSeg name, uint64_t bit_offset, uint32_t bit_count, FieldRules access_rules)
|
||||||
: NamedObject(Node::Type::FieldElement, name)
|
: NamedObject(Node::Type::FieldElement, name)
|
||||||
|
@ -53,6 +53,8 @@ namespace Kernel::ACPI::AML
|
||||||
, access_rules(access_rules)
|
, access_rules(access_rules)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
BAN::RefPtr<Node> evaluate() override;
|
||||||
|
|
||||||
void debug_print(int indent) const override;
|
void debug_print(int indent) const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -68,8 +70,8 @@ namespace Kernel::ACPI::AML
|
||||||
|
|
||||||
FieldRules access_rules;
|
FieldRules access_rules;
|
||||||
|
|
||||||
FieldElement* index_element = nullptr;
|
BAN::RefPtr<FieldElement> index_element = nullptr;
|
||||||
FieldElement* data_element = nullptr;
|
BAN::RefPtr<FieldElement> data_element = nullptr;
|
||||||
|
|
||||||
IndexFieldElement(NameSeg name, uint64_t bit_offset, uint32_t bit_count, FieldRules access_rules)
|
IndexFieldElement(NameSeg name, uint64_t bit_offset, uint32_t bit_count, FieldRules access_rules)
|
||||||
: NamedObject(Node::Type::IndexFieldElement, name)
|
: NamedObject(Node::Type::IndexFieldElement, name)
|
||||||
|
|
|
@ -0,0 +1,72 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <BAN/HashMap.h>
|
||||||
|
#include <kernel/ACPI/AML/Node.h>
|
||||||
|
#include <kernel/ACPI/AML/ParseContext.h>
|
||||||
|
#include <kernel/ACPI/AML/Pkg.h>
|
||||||
|
|
||||||
|
namespace Kernel::ACPI::AML
|
||||||
|
{
|
||||||
|
|
||||||
|
struct IfElse
|
||||||
|
{
|
||||||
|
static ParseResult parse(ParseContext& context)
|
||||||
|
{
|
||||||
|
ASSERT(context.aml_data.size() >= 1);
|
||||||
|
ASSERT(static_cast<Byte>(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<Byte>(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;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -18,9 +18,9 @@ namespace Kernel::ACPI::AML
|
||||||
|
|
||||||
Integer(uint64_t value) : Node(Node::Type::Integer), value(value) {}
|
Integer(uint64_t value) : Node(Node::Type::Integer), value(value) {}
|
||||||
|
|
||||||
BAN::Optional<uint64_t> as_integer() const override
|
BAN::RefPtr<AML::Node> evaluate() override
|
||||||
{
|
{
|
||||||
return value;
|
return MUST(BAN::RefPtr<Integer>::create(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
static ParseResult parse(BAN::ConstByteSpan& aml_data)
|
static ParseResult parse(BAN::ConstByteSpan& aml_data)
|
||||||
|
|
|
@ -11,6 +11,8 @@ namespace Kernel::ACPI::AML
|
||||||
|
|
||||||
struct Method : public AML::Scope
|
struct Method : public AML::Scope
|
||||||
{
|
{
|
||||||
|
using Arguments = BAN::Array<BAN::RefPtr<AML::Register>, 7>;
|
||||||
|
|
||||||
uint8_t arg_count;
|
uint8_t arg_count;
|
||||||
bool serialized;
|
bool serialized;
|
||||||
uint8_t sync_level;
|
uint8_t sync_level;
|
||||||
|
@ -49,10 +51,10 @@ namespace Kernel::ACPI::AML
|
||||||
(method_flags >> 3) & 0x01,
|
(method_flags >> 3) & 0x01,
|
||||||
method_flags >> 4
|
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;
|
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())
|
if (!method_scope.has_value())
|
||||||
return ParseResult::Failure;
|
return ParseResult::Failure;
|
||||||
method->term_list = method_pkg.value();
|
method->term_list = method_pkg.value();
|
||||||
|
@ -66,37 +68,32 @@ namespace Kernel::ACPI::AML
|
||||||
return ParseResult::Success;
|
return ParseResult::Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
BAN::Optional<BAN::RefPtr<AML::Node>> evaluate(BAN::RefPtr<AML::Namespace> root_namespace)
|
BAN::Optional<BAN::RefPtr<AML::Node>> evaluate(Arguments args)
|
||||||
{
|
{
|
||||||
ParseContext context;
|
ParseContext context;
|
||||||
context.root_namespace = root_namespace.ptr();
|
|
||||||
context.aml_data = term_list;
|
context.aml_data = term_list;
|
||||||
context.scope = scope;
|
context.scope = scope;
|
||||||
|
context.method_args = args;
|
||||||
AML_DEBUG_PRINTLN("Evaluating method {}", scope);
|
for (auto& local : context.method_locals)
|
||||||
|
local = MUST(BAN::RefPtr<AML::Register>::create());
|
||||||
|
|
||||||
BAN::Optional<BAN::RefPtr<AML::Node>> return_value;
|
BAN::Optional<BAN::RefPtr<AML::Node>> return_value;
|
||||||
|
|
||||||
ASSERT(arg_count == 0);
|
|
||||||
while (context.aml_data.size() > 0)
|
while (context.aml_data.size() > 0)
|
||||||
{
|
{
|
||||||
if (static_cast<AML::Byte>(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);
|
return_value = parse_result.node();
|
||||||
auto result = AML::parse_object(context);
|
|
||||||
if (result.success())
|
|
||||||
return_value = result.node();
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if (!parse_result.success())
|
||||||
auto object_result = AML::parse_object(context);
|
|
||||||
if (!object_result.success())
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (!context.created_objects.empty())
|
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();
|
context.created_objects.pop_back();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -39,7 +39,7 @@ namespace Kernel::ACPI::AML
|
||||||
}
|
}
|
||||||
|
|
||||||
auto mutex = MUST(BAN::RefPtr<Mutex>::create(name->path.back(), sync_level));
|
auto mutex = MUST(BAN::RefPtr<Mutex>::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;
|
return ParseResult::Failure;
|
||||||
|
|
||||||
#if AML_DEBUG_LEVEL >= 2
|
#if AML_DEBUG_LEVEL >= 2
|
||||||
|
|
|
@ -8,6 +8,7 @@ namespace Kernel::ACPI::AML
|
||||||
|
|
||||||
struct NamedObject : public Node
|
struct NamedObject : public Node
|
||||||
{
|
{
|
||||||
|
BAN::RefPtr<NamedObject> parent;
|
||||||
NameSeg name;
|
NameSeg name;
|
||||||
|
|
||||||
NamedObject(Node::Type type, NameSeg name) : Node(type), name(name) {}
|
NamedObject(Node::Type type, NameSeg name) : Node(type), name(name) {}
|
||||||
|
|
|
@ -7,6 +7,8 @@ namespace Kernel::ACPI::AML
|
||||||
|
|
||||||
struct Namespace : public AML::Scope
|
struct Namespace : public AML::Scope
|
||||||
{
|
{
|
||||||
|
static BAN::RefPtr<AML::Namespace> root_namespace();
|
||||||
|
|
||||||
Namespace(NameSeg name) : AML::Scope(Node::Type::Namespace, name) {}
|
Namespace(NameSeg name) : AML::Scope(Node::Type::Namespace, name) {}
|
||||||
|
|
||||||
static BAN::RefPtr<Namespace> parse(BAN::ConstByteSpan aml);
|
static BAN::RefPtr<Namespace> parse(BAN::ConstByteSpan aml);
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#include <BAN/Optional.h>
|
#include <BAN/Optional.h>
|
||||||
#include <BAN/RefPtr.h>
|
#include <BAN/RefPtr.h>
|
||||||
#include <BAN/Vector.h>
|
#include <BAN/Vector.h>
|
||||||
|
#include <kernel/ACPI/AML/Utils.h>
|
||||||
|
|
||||||
namespace Kernel::ACPI::AML
|
namespace Kernel::ACPI::AML
|
||||||
{
|
{
|
||||||
|
@ -24,6 +25,7 @@ namespace Kernel::ACPI::AML
|
||||||
OpRegion,
|
OpRegion,
|
||||||
Package,
|
Package,
|
||||||
Processor,
|
Processor,
|
||||||
|
Register,
|
||||||
String,
|
String,
|
||||||
};
|
};
|
||||||
const Type type;
|
const Type type;
|
||||||
|
@ -32,7 +34,10 @@ namespace Kernel::ACPI::AML
|
||||||
virtual ~Node() = default;
|
virtual ~Node() = default;
|
||||||
|
|
||||||
virtual bool is_scope() const { return false; }
|
virtual bool is_scope() const { return false; }
|
||||||
virtual BAN::Optional<uint64_t> as_integer() const { return {}; }
|
|
||||||
|
BAN::Optional<uint64_t> as_integer();
|
||||||
|
virtual BAN::RefPtr<AML::Node> evaluate() { AML_TODO("evaluate, type {}", static_cast<uint8_t>(type)); return nullptr; }
|
||||||
|
virtual bool store(BAN::RefPtr<AML::Node> source) { AML_TODO("store, type {}", static_cast<uint8_t>(type)); return false; }
|
||||||
|
|
||||||
virtual void debug_print(int indent) const = 0;
|
virtual void debug_print(int indent) const = 0;
|
||||||
};
|
};
|
||||||
|
@ -47,12 +52,25 @@ namespace Kernel::ACPI::AML
|
||||||
{
|
{
|
||||||
Success,
|
Success,
|
||||||
Failure,
|
Failure,
|
||||||
|
Returned,
|
||||||
};
|
};
|
||||||
|
|
||||||
ParseResult(Result success) : m_result(success) {}
|
ParseResult(Result success)
|
||||||
ParseResult(BAN::RefPtr<Node> node) : m_result(Result::Success), m_node(BAN::move(node)) { ASSERT(m_node); }
|
: m_result(success)
|
||||||
|
{}
|
||||||
|
ParseResult(Result success, BAN::RefPtr<Node> node)
|
||||||
|
: m_result(success)
|
||||||
|
, m_node(BAN::move(node))
|
||||||
|
{}
|
||||||
|
ParseResult(BAN::RefPtr<Node> node)
|
||||||
|
: m_result(Result::Success)
|
||||||
|
, m_node(BAN::move(node))
|
||||||
|
{
|
||||||
|
ASSERT(m_node);
|
||||||
|
}
|
||||||
|
|
||||||
bool success() const { return m_result == Result::Success; }
|
bool success() const { return m_result == Result::Success; }
|
||||||
|
bool returned() const { return m_result == Result::Returned; }
|
||||||
|
|
||||||
BAN::RefPtr<Node> node()
|
BAN::RefPtr<Node> node()
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <BAN/Array.h>
|
||||||
#include <BAN/ByteSpan.h>
|
#include <BAN/ByteSpan.h>
|
||||||
#include <BAN/LinkedList.h>
|
#include <BAN/LinkedList.h>
|
||||||
#include <kernel/ACPI/AML/NamedObject.h>
|
#include <kernel/ACPI/AML/NamedObject.h>
|
||||||
#include <kernel/ACPI/AML/Namespace.h>
|
#include <kernel/ACPI/AML/Namespace.h>
|
||||||
|
#include <kernel/ACPI/AML/Register.h>
|
||||||
|
|
||||||
namespace Kernel::ACPI::AML
|
namespace Kernel::ACPI::AML
|
||||||
{
|
{
|
||||||
|
@ -12,12 +14,14 @@ namespace Kernel::ACPI::AML
|
||||||
{
|
{
|
||||||
BAN::ConstByteSpan aml_data;
|
BAN::ConstByteSpan aml_data;
|
||||||
AML::NameString scope;
|
AML::NameString scope;
|
||||||
AML::Namespace* root_namespace;
|
|
||||||
|
|
||||||
// Used for cleaning up on method exit
|
// Used for cleaning up on method exit
|
||||||
// NOTE: This uses linked list instead of vector because
|
// NOTE: This uses linked list instead of vector because
|
||||||
// we don't really need large contiguous memory
|
// we don't really need large contiguous memory
|
||||||
BAN::LinkedList<AML::NameString> created_objects;
|
BAN::LinkedList<AML::NameString> created_objects;
|
||||||
|
|
||||||
|
BAN::Array<BAN::RefPtr<Register>, 7> method_args;
|
||||||
|
BAN::Array<BAN::RefPtr<Register>, 8> method_locals;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,7 +53,7 @@ namespace Kernel::ACPI::AML
|
||||||
processor_pkg = processor_pkg->slice(1);
|
processor_pkg = processor_pkg->slice(1);
|
||||||
|
|
||||||
auto processor = MUST(BAN::RefPtr<Processor>::create(name->path.back(), id, pblk_addr, pblk_len));
|
auto processor = MUST(BAN::RefPtr<Processor>::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 ParseResult::Failure;
|
||||||
|
|
||||||
return processor->enter_context_and_parse_term_list(context, name.value(), processor_pkg.value());
|
return processor->enter_context_and_parse_term_list(context, name.value(), processor_pkg.value());
|
||||||
|
|
|
@ -23,12 +23,15 @@ namespace Kernel::ACPI::AML
|
||||||
GenericSerialBus = 9,
|
GenericSerialBus = 9,
|
||||||
PCC = 10,
|
PCC = 10,
|
||||||
};
|
};
|
||||||
RegionSpace space;
|
RegionSpace region_space;
|
||||||
uint64_t offset;
|
uint64_t region_offset;
|
||||||
uint64_t length;
|
uint64_t region_length;
|
||||||
|
|
||||||
OpRegion(NameSeg name, RegionSpace space, uint64_t offset, uint64_t length)
|
OpRegion(NameSeg name, RegionSpace region_space, uint64_t region_offset, uint64_t region_length)
|
||||||
: NamedObject(Node::Type::OpRegion, name), space(space), offset(offset), length(length)
|
: NamedObject(Node::Type::OpRegion, name)
|
||||||
|
, region_space(region_space)
|
||||||
|
, region_offset(region_offset)
|
||||||
|
, region_length(region_length)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
static ParseResult parse(AML::ParseContext& context)
|
static ParseResult parse(AML::ParseContext& context)
|
||||||
|
@ -74,7 +77,7 @@ namespace Kernel::ACPI::AML
|
||||||
length.value()
|
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;
|
return ParseResult::Failure;
|
||||||
|
|
||||||
#if AML_DEBUG_LEVEL >= 2
|
#if AML_DEBUG_LEVEL >= 2
|
||||||
|
@ -88,7 +91,7 @@ namespace Kernel::ACPI::AML
|
||||||
virtual void debug_print(int indent) const override
|
virtual void debug_print(int indent) const override
|
||||||
{
|
{
|
||||||
BAN::StringView region_space_name;
|
BAN::StringView region_space_name;
|
||||||
switch (space)
|
switch (region_space)
|
||||||
{
|
{
|
||||||
case RegionSpace::SystemMemory: region_space_name = "SystemMemory"sv; break;
|
case RegionSpace::SystemMemory: region_space_name = "SystemMemory"sv; break;
|
||||||
case RegionSpace::SystemIO: region_space_name = "SystemIO"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_INDENT(indent);
|
||||||
AML_DEBUG_PRINT("OperationRegion(");
|
AML_DEBUG_PRINT("OperationRegion(");
|
||||||
name.debug_print();
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -0,0 +1,53 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <kernel/ACPI/AML/Node.h>
|
||||||
|
|
||||||
|
namespace Kernel::ACPI::AML
|
||||||
|
{
|
||||||
|
|
||||||
|
struct Register : public AML::Node
|
||||||
|
{
|
||||||
|
BAN::RefPtr<AML::Node> value;
|
||||||
|
|
||||||
|
Register()
|
||||||
|
: Node(Node::Type::Register)
|
||||||
|
{}
|
||||||
|
Register(BAN::RefPtr<AML::Node> value)
|
||||||
|
: Node(Node::Type::Register)
|
||||||
|
, value(value)
|
||||||
|
{}
|
||||||
|
|
||||||
|
BAN::RefPtr<AML::Node> evaluate() override
|
||||||
|
{
|
||||||
|
if (value)
|
||||||
|
return value->evaluate();
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
bool store(BAN::RefPtr<AML::Node> 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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,43 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <kernel/ACPI/AML/Bytes.h>
|
||||||
|
#include <kernel/ACPI/AML/ParseContext.h>
|
||||||
|
|
||||||
|
namespace Kernel::ACPI::AML
|
||||||
|
{
|
||||||
|
|
||||||
|
struct Store
|
||||||
|
{
|
||||||
|
static ParseResult parse(ParseContext& context)
|
||||||
|
{
|
||||||
|
ASSERT(context.aml_data.size() >= 1);
|
||||||
|
ASSERT(static_cast<Byte>(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;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -35,7 +35,7 @@ namespace Kernel::ACPI
|
||||||
|
|
||||||
auto dsdt = s_instance->get_header("DSDT", 0);
|
auto dsdt = s_instance->get_header("DSDT", 0);
|
||||||
ASSERT(dsdt);
|
ASSERT(dsdt);
|
||||||
s_instance->m_namespace = AMLParser::parse_table(*dsdt);
|
s_instance->m_namespace = AML::initialize_namespace(*dsdt);
|
||||||
|
|
||||||
#if ARCH(x86_64)
|
#if ARCH(x86_64)
|
||||||
lai_create_namespace();
|
lai_create_namespace();
|
||||||
|
|
|
@ -6,10 +6,7 @@
|
||||||
namespace Kernel::ACPI
|
namespace Kernel::ACPI
|
||||||
{
|
{
|
||||||
|
|
||||||
AMLParser::AMLParser() = default;
|
BAN::RefPtr<AML::Namespace> AML::initialize_namespace(const SDTHeader& header)
|
||||||
AMLParser::~AMLParser() = default;
|
|
||||||
|
|
||||||
BAN::RefPtr<AML::Namespace> AMLParser::parse_table(const SDTHeader& header)
|
|
||||||
{
|
{
|
||||||
dprintln("Parsing {}, {} bytes of AML", header, header.length);
|
dprintln("Parsing {}, {} bytes of AML", header, header.length);
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
#include <kernel/ACPI/AML/Field.h>
|
#include <kernel/ACPI/AML/Field.h>
|
||||||
|
#include <kernel/ACPI/AML/Integer.h>
|
||||||
|
|
||||||
namespace Kernel::ACPI
|
namespace Kernel::ACPI
|
||||||
{
|
{
|
||||||
|
@ -93,7 +94,7 @@ namespace Kernel::ACPI
|
||||||
if (!name_string.has_value())
|
if (!name_string.has_value())
|
||||||
return ParseResult::Failure;
|
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)
|
if (!op_region || op_region->type != AML::Node::Type::OpRegion)
|
||||||
{
|
{
|
||||||
AML_ERROR("FieldOp: {} does not name a valid OpRegion", name_string.value());
|
AML_ERROR("FieldOp: {} does not name a valid OpRegion", name_string.value());
|
||||||
|
@ -121,7 +122,7 @@ namespace Kernel::ACPI
|
||||||
|
|
||||||
NameString element_name;
|
NameString element_name;
|
||||||
MUST(element_name.path.push_back(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;
|
return ParseResult::Failure;
|
||||||
|
|
||||||
#if AML_DEBUG_LEVEL >= 2
|
#if AML_DEBUG_LEVEL >= 2
|
||||||
|
@ -133,6 +134,72 @@ namespace Kernel::ACPI
|
||||||
return ParseResult::Success;
|
return ParseResult::Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BAN::RefPtr<AML::Node> 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<uint8_t> ((byte_offset % PAGE_SIZE) / access_size); break;
|
||||||
|
case 2: result = PageTable::fast_page_as_sized<uint16_t>((byte_offset % PAGE_SIZE) / access_size); break;
|
||||||
|
case 4: result = PageTable::fast_page_as_sized<uint32_t>((byte_offset % PAGE_SIZE) / access_size); break;
|
||||||
|
case 8: result = PageTable::fast_page_as_sized<uint64_t>((byte_offset % PAGE_SIZE) / access_size); break;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
result >>= bit_offset % access_size;
|
||||||
|
result &= ((uint64_t)1 << bit_count) - 1;
|
||||||
|
return MUST(BAN::RefPtr<Integer>::create(result));
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
AML_TODO("FieldElement evaluate with region space {}", static_cast<uint8_t>(op_region->region_space));
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void AML::FieldElement::debug_print(int indent) const
|
void AML::FieldElement::debug_print(int indent) const
|
||||||
{
|
{
|
||||||
AML_DEBUG_PRINT_INDENT(indent);
|
AML_DEBUG_PRINT_INDENT(indent);
|
||||||
|
@ -158,7 +225,7 @@ namespace Kernel::ACPI
|
||||||
auto index_field_element_name = NameString::parse(field_pkg);
|
auto index_field_element_name = NameString::parse(field_pkg);
|
||||||
if (!index_field_element_name.has_value())
|
if (!index_field_element_name.has_value())
|
||||||
return ParseResult::Failure;
|
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)
|
if (!index_field_element || index_field_element->type != AML::Node::Type::FieldElement)
|
||||||
{
|
{
|
||||||
AML_ERROR("IndexField IndexName does not name a valid 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);
|
auto data_field_element_name = NameString::parse(field_pkg);
|
||||||
if (!data_field_element_name.has_value())
|
if (!data_field_element_name.has_value())
|
||||||
return ParseResult::Failure;
|
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)
|
if (!data_field_element || data_field_element->type != AML::Node::Type::FieldElement)
|
||||||
{
|
{
|
||||||
AML_ERROR("IndexField DataName does not name a valid FieldElement");
|
AML_ERROR("IndexField DataName does not name a valid FieldElement");
|
||||||
|
@ -197,7 +264,7 @@ namespace Kernel::ACPI
|
||||||
|
|
||||||
NameString element_name;
|
NameString element_name;
|
||||||
MUST(element_name.path.push_back(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;
|
return ParseResult::Failure;
|
||||||
|
|
||||||
#if AML_DEBUG_LEVEL >= 2
|
#if AML_DEBUG_LEVEL >= 2
|
||||||
|
|
|
@ -19,7 +19,7 @@ namespace Kernel::ACPI
|
||||||
return ParseResult::Failure;
|
return ParseResult::Failure;
|
||||||
|
|
||||||
auto name = MUST(BAN::RefPtr<Name>::create(name_string.value().path.back(), object.node()));
|
auto name = MUST(BAN::RefPtr<Name>::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;
|
return ParseResult::Failure;
|
||||||
|
|
||||||
#if AML_DEBUG_LEVEL >= 2
|
#if AML_DEBUG_LEVEL >= 2
|
||||||
|
|
|
@ -5,6 +5,14 @@
|
||||||
namespace Kernel::ACPI
|
namespace Kernel::ACPI
|
||||||
{
|
{
|
||||||
|
|
||||||
|
static BAN::RefPtr<AML::Namespace> s_root_namespace;
|
||||||
|
|
||||||
|
BAN::RefPtr<AML::Namespace> AML::Namespace::root_namespace()
|
||||||
|
{
|
||||||
|
ASSERT(s_root_namespace);
|
||||||
|
return s_root_namespace;
|
||||||
|
}
|
||||||
|
|
||||||
BAN::Optional<AML::NameString> AML::Namespace::resolve_path(const AML::NameString& relative_base, const AML::NameString& relative_path)
|
BAN::Optional<AML::NameString> AML::Namespace::resolve_path(const AML::NameString& relative_base, const AML::NameString& relative_path)
|
||||||
{
|
{
|
||||||
// Base must be non-empty absolute path
|
// Base must be non-empty absolute path
|
||||||
|
@ -143,6 +151,8 @@ namespace Kernel::ACPI
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
object->parent = parent_scope;
|
||||||
|
|
||||||
MUST(parent_scope->objects.insert(object->name, object));
|
MUST(parent_scope->objects.insert(object->name, object));
|
||||||
|
|
||||||
auto canonical_scope = resolve_path(parse_context.scope, object_path);
|
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)
|
bool AML::Namespace::remove_named_object(const AML::NameString& absolute_path)
|
||||||
{
|
{
|
||||||
auto canonical_path = resolve_path({}, absolute_path);
|
auto object = find_object({}, absolute_path);
|
||||||
if (!canonical_path.has_value())
|
if (!object)
|
||||||
{
|
{
|
||||||
AML_ERROR("Failed to resolve path");
|
AML_ERROR("Object {} not found", absolute_path);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (canonical_path->path.empty())
|
if (object.ptr() == this)
|
||||||
{
|
{
|
||||||
AML_ERROR("Trying to remove root object");
|
AML_ERROR("Trying to remove root object");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
BAN::RefPtr<NamedObject> parent_object = this;
|
auto parent = object->parent;
|
||||||
|
ASSERT(parent->is_scope());
|
||||||
|
|
||||||
for (size_t i = 0; i < canonical_path->path.size() - 1; i++)
|
auto* parent_scope = static_cast<Scope*>(parent.ptr());
|
||||||
{
|
parent_scope->objects.remove(object->name);
|
||||||
if (!parent_object->is_scope())
|
|
||||||
{
|
|
||||||
AML_ERROR("Parent object is not a scope");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto* parent_scope = static_cast<Scope*>(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<Scope*>(parent_object.ptr());
|
|
||||||
parent_scope->objects.remove(canonical_path->path.back());
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
BAN::RefPtr<AML::Namespace> AML::Namespace::parse(BAN::ConstByteSpan aml_data)
|
BAN::RefPtr<AML::Namespace> AML::Namespace::parse(BAN::ConstByteSpan aml_data)
|
||||||
{
|
{
|
||||||
auto result = MUST(BAN::RefPtr<Namespace>::create(NameSeg("\\"sv)));
|
s_root_namespace = MUST(BAN::RefPtr<Namespace>::create(NameSeg("\\"sv)));
|
||||||
|
|
||||||
AML::ParseContext context;
|
AML::ParseContext context;
|
||||||
context.scope = AML::NameString("\\"sv);
|
context.scope = AML::NameString("\\"sv);
|
||||||
context.aml_data = aml_data;
|
context.aml_data = aml_data;
|
||||||
context.root_namespace = result.ptr();
|
|
||||||
|
|
||||||
// Add predefined namespaces
|
// Add predefined namespaces
|
||||||
#define ADD_PREDEFIED_NAMESPACE(NAME) \
|
#define ADD_PREDEFIED_NAMESPACE(NAME) \
|
||||||
ASSERT(result->add_named_object(context, AML::NameString("\\" NAME), MUST(BAN::RefPtr<AML::Namespace>::create(NameSeg(NAME)))));
|
ASSERT(s_root_namespace->add_named_object(context, AML::NameString("\\" NAME), MUST(BAN::RefPtr<AML::Namespace>::create(NameSeg(NAME)))));
|
||||||
ADD_PREDEFIED_NAMESPACE("_GPE"sv);
|
ADD_PREDEFIED_NAMESPACE("_GPE"sv);
|
||||||
ADD_PREDEFIED_NAMESPACE("_PR"sv);
|
ADD_PREDEFIED_NAMESPACE("_PR"sv);
|
||||||
ADD_PREDEFIED_NAMESPACE("_SB"sv);
|
ADD_PREDEFIED_NAMESPACE("_SB"sv);
|
||||||
|
@ -236,7 +219,7 @@ namespace Kernel::ACPI
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return s_root_namespace;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
#include <kernel/ACPI/AML/Buffer.h>
|
#include <kernel/ACPI/AML/Buffer.h>
|
||||||
#include <kernel/ACPI/AML/Bytes.h>
|
#include <kernel/ACPI/AML/Bytes.h>
|
||||||
#include <kernel/ACPI/AML/Device.h>
|
#include <kernel/ACPI/AML/Device.h>
|
||||||
|
#include <kernel/ACPI/AML/Expression.h>
|
||||||
#include <kernel/ACPI/AML/Field.h>
|
#include <kernel/ACPI/AML/Field.h>
|
||||||
|
#include <kernel/ACPI/AML/IfElse.h>
|
||||||
#include <kernel/ACPI/AML/Integer.h>
|
#include <kernel/ACPI/AML/Integer.h>
|
||||||
#include <kernel/ACPI/AML/Method.h>
|
#include <kernel/ACPI/AML/Method.h>
|
||||||
#include <kernel/ACPI/AML/Mutex.h>
|
#include <kernel/ACPI/AML/Mutex.h>
|
||||||
|
@ -11,6 +13,7 @@
|
||||||
#include <kernel/ACPI/AML/ParseContext.h>
|
#include <kernel/ACPI/AML/ParseContext.h>
|
||||||
#include <kernel/ACPI/AML/Processor.h>
|
#include <kernel/ACPI/AML/Processor.h>
|
||||||
#include <kernel/ACPI/AML/Region.h>
|
#include <kernel/ACPI/AML/Region.h>
|
||||||
|
#include <kernel/ACPI/AML/Store.h>
|
||||||
#include <kernel/ACPI/AML/String.h>
|
#include <kernel/ACPI/AML/String.h>
|
||||||
#include <kernel/ACPI/AML/Utils.h>
|
#include <kernel/ACPI/AML/Utils.h>
|
||||||
|
|
||||||
|
@ -20,6 +23,18 @@ namespace Kernel::ACPI
|
||||||
AML::ParseResult AML::ParseResult::Failure = AML::ParseResult(AML::ParseResult::Result::Failure);
|
AML::ParseResult AML::ParseResult::Failure = AML::ParseResult(AML::ParseResult::Result::Failure);
|
||||||
AML::ParseResult AML::ParseResult::Success = AML::ParseResult(AML::ParseResult::Result::Success);
|
AML::ParseResult AML::ParseResult::Success = AML::ParseResult(AML::ParseResult::Result::Success);
|
||||||
|
|
||||||
|
BAN::Optional<uint64_t> AML::Node::as_integer()
|
||||||
|
{
|
||||||
|
if (type == Type::Integer)
|
||||||
|
return static_cast<const Integer*>(this)->value;
|
||||||
|
auto evaluated = evaluate();
|
||||||
|
if (!evaluated)
|
||||||
|
return {};
|
||||||
|
if (evaluated->type == Type::Integer)
|
||||||
|
return static_cast<const Integer*>(this)->value;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
AML::ParseResult AML::parse_object(AML::ParseContext& context)
|
AML::ParseResult AML::parse_object(AML::ParseContext& context)
|
||||||
{
|
{
|
||||||
if (context.aml_data.size() < 1)
|
if (context.aml_data.size() < 1)
|
||||||
|
@ -64,6 +79,53 @@ namespace Kernel::ACPI
|
||||||
return AML::Integer::parse(context.aml_data);
|
return AML::Integer::parse(context.aml_data);
|
||||||
case AML::Byte::StringPrefix:
|
case AML::Byte::StringPrefix:
|
||||||
return AML::String::parse(context);
|
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<uint8_t>(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<uint8_t>(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:
|
case AML::Byte::NameOp:
|
||||||
return AML::Name::parse(context);
|
return AML::Name::parse(context);
|
||||||
case AML::Byte::PackageOp:
|
case AML::Byte::PackageOp:
|
||||||
|
@ -74,6 +136,19 @@ namespace Kernel::ACPI
|
||||||
return AML::Buffer::parse(context);
|
return AML::Buffer::parse(context);
|
||||||
case AML::Byte::ScopeOp:
|
case AML::Byte::ScopeOp:
|
||||||
return AML::Scope::parse(context);
|
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:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -86,12 +161,36 @@ namespace Kernel::ACPI
|
||||||
auto name_string = AML::NameString::parse(context.aml_data);
|
auto name_string = AML::NameString::parse(context.aml_data);
|
||||||
if (!name_string.has_value())
|
if (!name_string.has_value())
|
||||||
return ParseResult::Failure;
|
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)
|
if (!aml_object)
|
||||||
{
|
{
|
||||||
AML_ERROR("NameString {} not found in namespace", name_string.value());
|
AML_ERROR("NameString {} not found in namespace", name_string.value());
|
||||||
return ParseResult::Failure;
|
return ParseResult::Failure;
|
||||||
}
|
}
|
||||||
|
if (aml_object->type == AML::Node::Type::Method)
|
||||||
|
{
|
||||||
|
auto* method = static_cast<AML::Method*>(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<AML::Register>::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);
|
return ParseResult(aml_object);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,7 @@ namespace Kernel::ACPI
|
||||||
if (!name_string.has_value())
|
if (!name_string.has_value())
|
||||||
return ParseResult::Failure;
|
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)
|
if (!named_object)
|
||||||
{
|
{
|
||||||
AML_ERROR("Scope name {} not found in namespace", name_string.value());
|
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)
|
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);
|
auto resolved_scope = Namespace::root_namespace()->resolve_path(outer_context.scope, name_string);
|
||||||
if (!scope.has_value())
|
if (!resolved_scope.has_value())
|
||||||
return ParseResult::Failure;
|
return ParseResult::Failure;
|
||||||
|
|
||||||
ParseContext scope_context;
|
ParseContext scope_context;
|
||||||
scope_context.root_namespace = outer_context.root_namespace;
|
scope_context.scope = resolved_scope.release_value();
|
||||||
scope_context.scope = scope.release_value();
|
|
||||||
scope_context.aml_data = aml_data;
|
scope_context.aml_data = aml_data;
|
||||||
|
scope_context.method_args = outer_context.method_args;
|
||||||
while (scope_context.aml_data.size() > 0)
|
while (scope_context.aml_data.size() > 0)
|
||||||
{
|
{
|
||||||
auto object_result = AML::parse_object(scope_context);
|
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())
|
if (!object_result.success())
|
||||||
return ParseResult::Failure;
|
return ParseResult::Failure;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue