Kernel: Start working on AML method evaluations
Also fix namespace lookup and scope creations.
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <kernel/ACPI/AML/Method.h>
|
||||
#include <kernel/ACPI/AML/ParseContext.h>
|
||||
#include <kernel/ACPI/AML/Pkg.h>
|
||||
#include <kernel/ACPI/AML/Scope.h>
|
||||
@@ -9,7 +10,9 @@ namespace Kernel::ACPI::AML
|
||||
|
||||
struct Device : public AML::Scope
|
||||
{
|
||||
Device(NameSeg name) : Scope(name, Node::Type::Device) {}
|
||||
Device(NameSeg name)
|
||||
: Scope(Node::Type::Device, name)
|
||||
{}
|
||||
|
||||
static ParseResult parse(ParseContext& context)
|
||||
{
|
||||
@@ -27,12 +30,65 @@ namespace Kernel::ACPI::AML
|
||||
return ParseResult::Failure;
|
||||
|
||||
auto device = MUST(BAN::RefPtr<Device>::create(name_string->path.back()));
|
||||
if (!context.root_namespace->add_named_object(context.scope.span(), name_string.value(), device))
|
||||
if (!context.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<AML::Namespace> root_namespace)
|
||||
{
|
||||
bool run_ini = true;
|
||||
bool init_children = true;
|
||||
|
||||
auto _sta = root_namespace->find_object(scope, NameString("_STA"sv));
|
||||
if (_sta && _sta->type == Node::Type::Method)
|
||||
{
|
||||
auto* method = static_cast<Method*>(_sta.ptr());
|
||||
auto result = method->evaluate(root_namespace);
|
||||
if (!result.has_value())
|
||||
{
|
||||
AML_ERROR("Failed to evaluate {}._STA", scope);
|
||||
return;
|
||||
}
|
||||
if (!result.value())
|
||||
{
|
||||
AML_ERROR("Failed to evaluate {}._STA, return value is null", scope);
|
||||
return;
|
||||
}
|
||||
auto result_val = result.value()->as_integer();
|
||||
if (!result_val.has_value())
|
||||
{
|
||||
AML_ERROR("Failed to evaluate {}._STA, return value could not be resolved to integer", scope);
|
||||
return;
|
||||
}
|
||||
run_ini = (result_val.value() & 0x01);
|
||||
init_children = run_ini || (result_val.value() & 0x02);
|
||||
}
|
||||
|
||||
if (run_ini)
|
||||
{
|
||||
auto _ini = root_namespace->find_object(scope, NameString("_INI"sv));
|
||||
if (_ini && _ini->type == Node::Type::Method)
|
||||
{
|
||||
auto* method = static_cast<Method*>(_ini.ptr());
|
||||
method->evaluate(root_namespace);
|
||||
}
|
||||
}
|
||||
|
||||
if (init_children)
|
||||
{
|
||||
for (auto& [_, child] : objects)
|
||||
{
|
||||
if (child->type == Node::Type::Device)
|
||||
{
|
||||
auto* device = static_cast<Device*>(child.ptr());
|
||||
device->initialize(root_namespace);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
virtual void debug_print(int indent) const override
|
||||
{
|
||||
AML_DEBUG_PRINT_INDENT(indent);
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#include <kernel/ACPI/AML/Bytes.h>
|
||||
#include <kernel/ACPI/AML/NamedObject.h>
|
||||
#include <kernel/ACPI/AML/Namespace.h>
|
||||
#include <kernel/ACPI/AML/ParseContext.h>
|
||||
#include <kernel/ACPI/AML/Pkg.h>
|
||||
#include <kernel/ACPI/AML/Scope.h>
|
||||
|
||||
namespace Kernel::ACPI::AML
|
||||
{
|
||||
|
||||
struct Method : public AML::NamedObject
|
||||
struct Method : public AML::Scope
|
||||
{
|
||||
uint8_t arg_count;
|
||||
bool serialized;
|
||||
@@ -16,12 +17,11 @@ namespace Kernel::ACPI::AML
|
||||
|
||||
BAN::ConstByteSpan term_list;
|
||||
|
||||
Method(AML::NameSeg name, uint8_t arg_count, bool serialized, uint8_t sync_level, BAN::ConstByteSpan term_list)
|
||||
: AML::NamedObject(Node::Type::Method, name)
|
||||
Method(AML::NameSeg name, uint8_t arg_count, bool serialized, uint8_t sync_level)
|
||||
: AML::Scope(Node::Type::Method, name)
|
||||
, arg_count(arg_count)
|
||||
, serialized(serialized)
|
||||
, sync_level(sync_level)
|
||||
, term_list(term_list)
|
||||
{}
|
||||
|
||||
static ParseResult parse(AML::ParseContext& context)
|
||||
@@ -47,13 +47,17 @@ namespace Kernel::ACPI::AML
|
||||
name_string.value().path.back(),
|
||||
method_flags & 0x07,
|
||||
(method_flags >> 3) & 0x01,
|
||||
method_flags >> 4,
|
||||
method_pkg.value()
|
||||
method_flags >> 4
|
||||
));
|
||||
|
||||
if (!context.root_namespace->add_named_object(context.scope.span(), name_string.value(), method))
|
||||
if (!context.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());
|
||||
if (!method_scope.has_value())
|
||||
return ParseResult::Failure;
|
||||
method->term_list = method_pkg.value();
|
||||
method->scope = method_scope.release_value();
|
||||
|
||||
#if AML_DEBUG_LEVEL >= 2
|
||||
method->debug_print(0);
|
||||
AML_DEBUG_PRINTLN("");
|
||||
@@ -62,6 +66,43 @@ namespace Kernel::ACPI::AML
|
||||
return ParseResult::Success;
|
||||
}
|
||||
|
||||
BAN::Optional<BAN::RefPtr<AML::Node>> evaluate(BAN::RefPtr<AML::Namespace> root_namespace)
|
||||
{
|
||||
ParseContext context;
|
||||
context.root_namespace = root_namespace.ptr();
|
||||
context.aml_data = term_list;
|
||||
context.scope = scope;
|
||||
|
||||
AML_DEBUG_PRINTLN("Evaluating method {}", scope);
|
||||
|
||||
BAN::Optional<BAN::RefPtr<AML::Node>> return_value;
|
||||
|
||||
ASSERT(arg_count == 0);
|
||||
while (context.aml_data.size() > 0)
|
||||
{
|
||||
if (static_cast<AML::Byte>(context.aml_data[0]) == AML::Byte::ReturnOp)
|
||||
{
|
||||
context.aml_data = context.aml_data.slice(1);
|
||||
auto result = AML::parse_object(context);
|
||||
if (result.success())
|
||||
return_value = result.node();
|
||||
break;
|
||||
}
|
||||
|
||||
auto object_result = AML::parse_object(context);
|
||||
if (!object_result.success())
|
||||
break;
|
||||
}
|
||||
|
||||
while (!context.created_objects.empty())
|
||||
{
|
||||
root_namespace->remove_named_object(context.created_objects.back());
|
||||
context.created_objects.pop_back();
|
||||
}
|
||||
|
||||
return return_value;
|
||||
}
|
||||
|
||||
virtual void debug_print(int indent) const override
|
||||
{
|
||||
AML_DEBUG_PRINT_INDENT(indent);
|
||||
|
||||
@@ -39,7 +39,7 @@ namespace Kernel::ACPI::AML
|
||||
}
|
||||
|
||||
auto mutex = MUST(BAN::RefPtr<Mutex>::create(name->path.back(), sync_level));
|
||||
if (!context.root_namespace->add_named_object(context.scope.span(), name.value(), mutex))
|
||||
if (!context.root_namespace->add_named_object(context, name.value(), mutex))
|
||||
return ParseResult::Failure;
|
||||
|
||||
#if AML_DEBUG_LEVEL >= 2
|
||||
|
||||
@@ -70,6 +70,42 @@ namespace Kernel::ACPI::AML
|
||||
BAN::String prefix;
|
||||
BAN::Vector<NameSeg> path;
|
||||
|
||||
NameString() = default;
|
||||
NameString(BAN::StringView str)
|
||||
{
|
||||
if (!str.empty() && str.front() == '\\')
|
||||
{
|
||||
MUST(prefix.push_back('\\'));
|
||||
str = str.substring(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
while (str.size() > 0 && str.front() == '^')
|
||||
{
|
||||
MUST(prefix.push_back('^'));
|
||||
str = str.substring(1);
|
||||
}
|
||||
}
|
||||
|
||||
while (!str.empty())
|
||||
{
|
||||
ASSERT(str[0] != '.');
|
||||
size_t len = 1;
|
||||
while (len < str.size() && str[len] != '.')
|
||||
len++;
|
||||
ASSERT(len <= 4);
|
||||
|
||||
MUST(path.push_back(NameSeg(str.substring(0, len))));
|
||||
str = str.substring(len);
|
||||
|
||||
if (!str.empty())
|
||||
{
|
||||
ASSERT(str[0] == '.');
|
||||
str = str.substring(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static BAN::Optional<NameString> parse(BAN::ConstByteSpan& aml_data)
|
||||
{
|
||||
if (aml_data.size() == 0)
|
||||
@@ -154,4 +190,27 @@ namespace BAN
|
||||
}
|
||||
};
|
||||
|
||||
template<typename F>
|
||||
void Formatter::print_argument(F putc, const Kernel::ACPI::AML::NameSeg& name_seg, const ValueFormat&)
|
||||
{
|
||||
size_t len = 4;
|
||||
while (len > 0 && name_seg.chars[len - 1] == '_')
|
||||
len--;
|
||||
for (size_t i = 0; i < len; i++)
|
||||
putc(name_seg.chars[i]);
|
||||
}
|
||||
|
||||
template<typename F>
|
||||
void Formatter::print_argument(F putc, const Kernel::ACPI::AML::NameString& name_string, const ValueFormat&)
|
||||
{
|
||||
print_argument(putc, name_string.prefix, {});
|
||||
if (!name_string.path.empty())
|
||||
print_argument(putc, name_string.path.front(), {});
|
||||
for (size_t i = 1; i < name_string.path.size(); i++)
|
||||
{
|
||||
putc('.');
|
||||
print_argument(putc, name_string.path[i], {});
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -7,17 +7,20 @@ namespace Kernel::ACPI::AML
|
||||
|
||||
struct Namespace : public AML::Scope
|
||||
{
|
||||
Namespace() : AML::Scope(NameSeg("\\"sv)) {}
|
||||
Namespace(NameSeg name) : AML::Scope(Node::Type::Namespace, name) {}
|
||||
|
||||
static BAN::RefPtr<Namespace> parse(BAN::ConstByteSpan aml);
|
||||
|
||||
BAN::Optional<BAN::Vector<AML::NameSeg>> resolve_path(BAN::Span<const AML::NameSeg> parsing_scope, const AML::NameString& relative_path);
|
||||
BAN::Optional<AML::NameString> resolve_path(const AML::NameString& relative_base, const AML::NameString& relative_path);
|
||||
|
||||
// Find an object in the namespace. Returns nullptr if the object is not found.
|
||||
BAN::RefPtr<NamedObject> find_object(BAN::Span<const AML::NameSeg> parsing_scope, const AML::NameString& relative_path);
|
||||
BAN::RefPtr<NamedObject> find_object(const AML::NameString& relative_base, const AML::NameString& relative_path);
|
||||
|
||||
// Add an object to the namespace. Returns false if the parent object could not be added.
|
||||
bool add_named_object(BAN::Span<const AML::NameSeg> parsing_scope, const AML::NameString& object_path, BAN::RefPtr<NamedObject> object);
|
||||
bool add_named_object(ParseContext&, const AML::NameString& object_path, BAN::RefPtr<NamedObject> object);
|
||||
|
||||
// Remove an object from the namespace. Returns false if the object could not be removed.
|
||||
bool remove_named_object(const AML::NameString& absolute_path);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -20,10 +20,10 @@ namespace Kernel::ACPI::AML
|
||||
Method,
|
||||
Mutex,
|
||||
Name,
|
||||
Namespace,
|
||||
OpRegion,
|
||||
Package,
|
||||
Processor,
|
||||
Scope,
|
||||
String,
|
||||
};
|
||||
const Type type;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <BAN/ByteSpan.h>
|
||||
#include <BAN/Vector.h>
|
||||
#include <BAN/LinkedList.h>
|
||||
#include <kernel/ACPI/AML/NamedObject.h>
|
||||
#include <kernel/ACPI/AML/Namespace.h>
|
||||
|
||||
@@ -10,9 +10,14 @@ namespace Kernel::ACPI::AML
|
||||
|
||||
struct ParseContext
|
||||
{
|
||||
BAN::ConstByteSpan aml_data;
|
||||
BAN::Vector<AML::NameSeg> scope;
|
||||
struct Namespace* root_namespace;
|
||||
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<AML::NameString> created_objects;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ namespace Kernel::ACPI::AML
|
||||
uint8_t pblk_len;
|
||||
|
||||
Processor(NameSeg name, uint8_t id, uint32_t pblk_addr, uint8_t pblk_len)
|
||||
: Scope(name, Node::Type::Processor)
|
||||
: Scope(Node::Type::Processor, name)
|
||||
, id(id)
|
||||
, pblk_addr(pblk_addr)
|
||||
, pblk_len(pblk_len)
|
||||
@@ -53,7 +53,7 @@ namespace Kernel::ACPI::AML
|
||||
processor_pkg = processor_pkg->slice(1);
|
||||
|
||||
auto processor = MUST(BAN::RefPtr<Processor>::create(name->path.back(), id, pblk_addr, pblk_len));
|
||||
if (!context.root_namespace->add_named_object(context.scope.span(), name.value(), processor))
|
||||
if (!context.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());
|
||||
|
||||
@@ -74,7 +74,7 @@ namespace Kernel::ACPI::AML
|
||||
length.value()
|
||||
));
|
||||
|
||||
if (!context.root_namespace->add_named_object(context.scope.span(), name.value(), op_region))
|
||||
if (!context.root_namespace->add_named_object(context, name.value(), op_region))
|
||||
return ParseResult::Failure;
|
||||
|
||||
#if AML_DEBUG_LEVEL >= 2
|
||||
|
||||
@@ -10,8 +10,11 @@ namespace Kernel::ACPI::AML
|
||||
struct Scope : public AML::NamedObject
|
||||
{
|
||||
BAN::HashMap<NameSeg, BAN::RefPtr<NamedObject>> objects;
|
||||
AML::NameString scope;
|
||||
|
||||
Scope(NameSeg name, Node::Type type = Node::Type::Scope) : NamedObject(type, name) {}
|
||||
Scope(Node::Type type, NameSeg name)
|
||||
: NamedObject(type, name)
|
||||
{}
|
||||
|
||||
virtual bool is_scope() const override { return true; }
|
||||
|
||||
|
||||
Reference in New Issue
Block a user