Kernel: Start working on AML method evaluations
Also fix namespace lookup and scope creations.
This commit is contained in:
parent
b16e65168f
commit
23fa39121c
|
@ -1,5 +1,6 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <kernel/ACPI/AML/Method.h>
|
||||||
#include <kernel/ACPI/AML/ParseContext.h>
|
#include <kernel/ACPI/AML/ParseContext.h>
|
||||||
#include <kernel/ACPI/AML/Pkg.h>
|
#include <kernel/ACPI/AML/Pkg.h>
|
||||||
#include <kernel/ACPI/AML/Scope.h>
|
#include <kernel/ACPI/AML/Scope.h>
|
||||||
|
@ -9,7 +10,9 @@ namespace Kernel::ACPI::AML
|
||||||
|
|
||||||
struct Device : public AML::Scope
|
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)
|
static ParseResult parse(ParseContext& context)
|
||||||
{
|
{
|
||||||
|
@ -27,12 +30,65 @@ 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.scope.span(), name_string.value(), device))
|
if (!context.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)
|
||||||
|
{
|
||||||
|
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
|
virtual void debug_print(int indent) const override
|
||||||
{
|
{
|
||||||
AML_DEBUG_PRINT_INDENT(indent);
|
AML_DEBUG_PRINT_INDENT(indent);
|
||||||
|
|
|
@ -1,14 +1,15 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <kernel/ACPI/AML/Bytes.h>
|
#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/ParseContext.h>
|
||||||
#include <kernel/ACPI/AML/Pkg.h>
|
#include <kernel/ACPI/AML/Pkg.h>
|
||||||
|
#include <kernel/ACPI/AML/Scope.h>
|
||||||
|
|
||||||
namespace Kernel::ACPI::AML
|
namespace Kernel::ACPI::AML
|
||||||
{
|
{
|
||||||
|
|
||||||
struct Method : public AML::NamedObject
|
struct Method : public AML::Scope
|
||||||
{
|
{
|
||||||
uint8_t arg_count;
|
uint8_t arg_count;
|
||||||
bool serialized;
|
bool serialized;
|
||||||
|
@ -16,12 +17,11 @@ namespace Kernel::ACPI::AML
|
||||||
|
|
||||||
BAN::ConstByteSpan term_list;
|
BAN::ConstByteSpan term_list;
|
||||||
|
|
||||||
Method(AML::NameSeg name, uint8_t arg_count, bool serialized, uint8_t sync_level, BAN::ConstByteSpan term_list)
|
Method(AML::NameSeg name, uint8_t arg_count, bool serialized, uint8_t sync_level)
|
||||||
: AML::NamedObject(Node::Type::Method, name)
|
: AML::Scope(Node::Type::Method, name)
|
||||||
, arg_count(arg_count)
|
, arg_count(arg_count)
|
||||||
, serialized(serialized)
|
, serialized(serialized)
|
||||||
, sync_level(sync_level)
|
, sync_level(sync_level)
|
||||||
, term_list(term_list)
|
|
||||||
{}
|
{}
|
||||||
|
|
||||||
static ParseResult parse(AML::ParseContext& context)
|
static ParseResult parse(AML::ParseContext& context)
|
||||||
|
@ -47,13 +47,17 @@ namespace Kernel::ACPI::AML
|
||||||
name_string.value().path.back(),
|
name_string.value().path.back(),
|
||||||
method_flags & 0x07,
|
method_flags & 0x07,
|
||||||
(method_flags >> 3) & 0x01,
|
(method_flags >> 3) & 0x01,
|
||||||
method_flags >> 4,
|
method_flags >> 4
|
||||||
method_pkg.value()
|
|
||||||
));
|
));
|
||||||
|
if (!context.root_namespace->add_named_object(context, name_string.value(), method))
|
||||||
if (!context.root_namespace->add_named_object(context.scope.span(), name_string.value(), method))
|
|
||||||
return ParseResult::Failure;
|
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
|
#if AML_DEBUG_LEVEL >= 2
|
||||||
method->debug_print(0);
|
method->debug_print(0);
|
||||||
AML_DEBUG_PRINTLN("");
|
AML_DEBUG_PRINTLN("");
|
||||||
|
@ -62,6 +66,43 @@ namespace Kernel::ACPI::AML
|
||||||
return ParseResult::Success;
|
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
|
virtual void debug_print(int indent) const override
|
||||||
{
|
{
|
||||||
AML_DEBUG_PRINT_INDENT(indent);
|
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));
|
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;
|
return ParseResult::Failure;
|
||||||
|
|
||||||
#if AML_DEBUG_LEVEL >= 2
|
#if AML_DEBUG_LEVEL >= 2
|
||||||
|
|
|
@ -70,6 +70,42 @@ namespace Kernel::ACPI::AML
|
||||||
BAN::String prefix;
|
BAN::String prefix;
|
||||||
BAN::Vector<NameSeg> path;
|
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)
|
static BAN::Optional<NameString> parse(BAN::ConstByteSpan& aml_data)
|
||||||
{
|
{
|
||||||
if (aml_data.size() == 0)
|
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
|
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);
|
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.
|
// 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.
|
// 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,
|
Method,
|
||||||
Mutex,
|
Mutex,
|
||||||
Name,
|
Name,
|
||||||
|
Namespace,
|
||||||
OpRegion,
|
OpRegion,
|
||||||
Package,
|
Package,
|
||||||
Processor,
|
Processor,
|
||||||
Scope,
|
|
||||||
String,
|
String,
|
||||||
};
|
};
|
||||||
const Type type;
|
const Type type;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <BAN/ByteSpan.h>
|
#include <BAN/ByteSpan.h>
|
||||||
#include <BAN/Vector.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>
|
||||||
|
|
||||||
|
@ -10,9 +10,14 @@ namespace Kernel::ACPI::AML
|
||||||
|
|
||||||
struct ParseContext
|
struct ParseContext
|
||||||
{
|
{
|
||||||
BAN::ConstByteSpan aml_data;
|
BAN::ConstByteSpan aml_data;
|
||||||
BAN::Vector<AML::NameSeg> scope;
|
AML::NameString scope;
|
||||||
struct Namespace* root_namespace;
|
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;
|
uint8_t pblk_len;
|
||||||
|
|
||||||
Processor(NameSeg name, uint8_t id, uint32_t pblk_addr, 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)
|
, id(id)
|
||||||
, pblk_addr(pblk_addr)
|
, pblk_addr(pblk_addr)
|
||||||
, pblk_len(pblk_len)
|
, pblk_len(pblk_len)
|
||||||
|
@ -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.scope.span(), name.value(), processor))
|
if (!context.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());
|
||||||
|
|
|
@ -74,7 +74,7 @@ namespace Kernel::ACPI::AML
|
||||||
length.value()
|
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;
|
return ParseResult::Failure;
|
||||||
|
|
||||||
#if AML_DEBUG_LEVEL >= 2
|
#if AML_DEBUG_LEVEL >= 2
|
||||||
|
|
|
@ -10,8 +10,11 @@ namespace Kernel::ACPI::AML
|
||||||
struct Scope : public AML::NamedObject
|
struct Scope : public AML::NamedObject
|
||||||
{
|
{
|
||||||
BAN::HashMap<NameSeg, BAN::RefPtr<NamedObject>> objects;
|
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; }
|
virtual bool is_scope() const override { return true; }
|
||||||
|
|
||||||
|
|
|
@ -93,10 +93,10 @@ 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.span(), name_string.value());
|
auto op_region = context.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("Field RegionName does not name a valid OpRegion");
|
AML_ERROR("FieldOp: {} does not name a valid OpRegion", name_string.value());
|
||||||
return ParseResult::Failure;
|
return ParseResult::Failure;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -121,7 +121,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.scope.span(), element_name, element))
|
if (!context.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
|
||||||
|
@ -158,7 +158,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.span(), index_field_element_name.value());
|
auto index_field_element = context.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 +168,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.span(), data_field_element_name.value());
|
auto data_field_element = context.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 +197,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.scope.span(), element_name, element))
|
if (!context.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.scope.span(), name_string.value(), name))
|
if (!context.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,69 +5,117 @@
|
||||||
namespace Kernel::ACPI
|
namespace Kernel::ACPI
|
||||||
{
|
{
|
||||||
|
|
||||||
BAN::Optional<BAN::Vector<AML::NameSeg>> AML::Namespace::resolve_path(BAN::Span<const AML::NameSeg> parsing_scope, const AML::NameString& relative_path)
|
BAN::Optional<AML::NameString> AML::Namespace::resolve_path(const AML::NameString& relative_base, const AML::NameString& relative_path)
|
||||||
{
|
{
|
||||||
BAN::Vector<NameSeg> canonical_path;
|
// Base must be non-empty absolute path
|
||||||
|
ASSERT(relative_base.prefix == "\\"sv || relative_base.path.empty());
|
||||||
|
|
||||||
if (!relative_path.prefix.empty())
|
// Do absolute path lookup
|
||||||
|
if (!relative_path.prefix.empty() || relative_path.path.size() != 1)
|
||||||
{
|
{
|
||||||
if (relative_path.prefix[0] == '\\')
|
AML::NameString absolute_path;
|
||||||
|
MUST(absolute_path.prefix.push_back('\\'));
|
||||||
|
|
||||||
|
// Resolve root and parent references
|
||||||
|
if (relative_path.prefix == "\\"sv)
|
||||||
;
|
;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (parsing_scope.size() < relative_path.prefix.size())
|
if (relative_path.prefix.size() > relative_base.path.size())
|
||||||
{
|
{
|
||||||
AML_ERROR("Trying to resolve parent of root object");
|
AML_ERROR("Trying to resolve parent of root object");
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
for (size_t i = 0; i < parsing_scope.size() - relative_path.prefix.size(); i++)
|
for (size_t i = 0; i < relative_base.path.size() - relative_path.prefix.size(); i++)
|
||||||
MUST(canonical_path.push_back(parsing_scope[i]));
|
MUST(absolute_path.path.push_back(relative_base.path[i]));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Append relative path
|
||||||
|
for (const auto& seg : relative_path.path)
|
||||||
|
MUST(absolute_path.path.push_back(seg));
|
||||||
|
|
||||||
|
// Validate path
|
||||||
|
BAN::RefPtr<AML::NamedObject> current_node = this;
|
||||||
|
for (const auto& seg : absolute_path.path)
|
||||||
|
{
|
||||||
|
if (!current_node->is_scope())
|
||||||
|
return {};
|
||||||
|
|
||||||
|
auto* current_scope = static_cast<AML::Scope*>(current_node.ptr());
|
||||||
|
auto it = current_scope->objects.find(seg);
|
||||||
|
if (it == current_scope->objects.end())
|
||||||
|
return {};
|
||||||
|
|
||||||
|
current_node = it->value;
|
||||||
|
}
|
||||||
|
return absolute_path;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Resolve with namespace search rules (ACPI Spec 6.4 - Section 5.3)
|
||||||
|
|
||||||
|
AML::NameString last_match_path;
|
||||||
|
AML::NameSeg target_seg = relative_path.path.back();
|
||||||
|
|
||||||
|
BAN::RefPtr<AML::Scope> current_scope = this;
|
||||||
|
AML::NameString current_path;
|
||||||
|
|
||||||
|
// Check root namespace
|
||||||
|
{
|
||||||
|
// If scope contains object with the same name as the segment, update last match
|
||||||
|
if (current_scope->objects.contains(target_seg))
|
||||||
|
{
|
||||||
|
last_match_path = current_path;
|
||||||
|
MUST(last_match_path.path.push_back(target_seg));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
// Check base base path
|
||||||
|
for (const auto& seg : relative_base.path)
|
||||||
{
|
{
|
||||||
for (auto seg : parsing_scope)
|
auto next_node = current_scope->objects[seg];
|
||||||
MUST(canonical_path.push_back(seg));
|
ASSERT(next_node && next_node->is_scope());
|
||||||
|
|
||||||
|
current_scope = static_cast<AML::Scope*>(next_node.ptr());
|
||||||
|
MUST(current_path.path.push_back(seg));
|
||||||
|
|
||||||
|
// If scope contains object with the same name as the segment, update last match
|
||||||
|
if (current_scope->objects.contains(target_seg))
|
||||||
|
{
|
||||||
|
last_match_path = current_path;
|
||||||
|
MUST(last_match_path.path.push_back(target_seg));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const auto& seg : relative_path.path)
|
if (!last_match_path.path.empty())
|
||||||
MUST(canonical_path.push_back(seg));
|
{
|
||||||
|
MUST(last_match_path.prefix.push_back('\\'));
|
||||||
|
return last_match_path;
|
||||||
|
}
|
||||||
|
|
||||||
return canonical_path;
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
BAN::RefPtr<AML::NamedObject> AML::Namespace::find_object(BAN::Span<const AML::NameSeg> parsing_scope, const AML::NameString& relative_path)
|
BAN::RefPtr<AML::NamedObject> AML::Namespace::find_object(const AML::NameString& relative_base, const AML::NameString& relative_path)
|
||||||
{
|
{
|
||||||
auto canonical_path = resolve_path(parsing_scope, relative_path);
|
auto canonical_path = resolve_path(relative_base, relative_path);
|
||||||
if (!canonical_path.has_value())
|
if (!canonical_path.has_value())
|
||||||
return nullptr;
|
return nullptr;
|
||||||
if (canonical_path->empty())
|
if (canonical_path->path.empty())
|
||||||
return this;
|
return this;
|
||||||
|
|
||||||
BAN::RefPtr<NamedObject> parent_object = this;
|
BAN::RefPtr<NamedObject> node = this;
|
||||||
|
for (const auto& seg : canonical_path->path)
|
||||||
for (const auto& seg : canonical_path.value())
|
|
||||||
{
|
{
|
||||||
if (!parent_object->is_scope())
|
// Resolve path validates that all nodes are scopes
|
||||||
{
|
ASSERT(node->is_scope());
|
||||||
AML_ERROR("Parent object is not a scope");
|
node = static_cast<Scope*>(node.ptr())->objects[seg];
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto* parent_scope = static_cast<Scope*>(parent_object.ptr());
|
|
||||||
|
|
||||||
auto it = parent_scope->objects.find(seg);
|
|
||||||
if (it == parent_scope->objects.end())
|
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
parent_object = it->value;
|
|
||||||
ASSERT(parent_object);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return parent_object;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AML::Namespace::add_named_object(BAN::Span<const NameSeg> parsing_scope, const AML::NameString& object_path, BAN::RefPtr<NamedObject> object)
|
bool AML::Namespace::add_named_object(ParseContext& parse_context, const AML::NameString& object_path, BAN::RefPtr<NamedObject> object)
|
||||||
{
|
{
|
||||||
ASSERT(!object_path.path.empty());
|
ASSERT(!object_path.path.empty());
|
||||||
ASSERT(object_path.path.back() == object->name);
|
ASSERT(object_path.path.back() == object->name);
|
||||||
|
@ -75,7 +123,7 @@ namespace Kernel::ACPI
|
||||||
auto parent_path = object_path;
|
auto parent_path = object_path;
|
||||||
parent_path.path.pop_back();
|
parent_path.path.pop_back();
|
||||||
|
|
||||||
auto parent_object = find_object(parsing_scope, parent_path);
|
auto parent_object = find_object(parse_context.scope, parent_path);
|
||||||
if (!parent_object)
|
if (!parent_object)
|
||||||
{
|
{
|
||||||
AML_ERROR("Parent object not found");
|
AML_ERROR("Parent object not found");
|
||||||
|
@ -96,17 +144,88 @@ namespace Kernel::ACPI
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
||||||
|
ASSERT(canonical_scope.has_value());
|
||||||
|
if (object->is_scope())
|
||||||
|
{
|
||||||
|
auto* scope = static_cast<Scope*>(object.ptr());
|
||||||
|
scope->scope = canonical_scope.value();
|
||||||
|
}
|
||||||
|
MUST(parse_context.created_objects.push_back(BAN::move(canonical_scope.release_value())));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AML::Namespace::remove_named_object(const AML::NameString& absolute_path)
|
||||||
|
{
|
||||||
|
auto canonical_path = resolve_path({}, absolute_path);
|
||||||
|
if (!canonical_path.has_value())
|
||||||
|
{
|
||||||
|
AML_ERROR("Failed to resolve path");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (canonical_path->path.empty())
|
||||||
|
{
|
||||||
|
AML_ERROR("Trying to remove root object");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
BAN::RefPtr<NamedObject> parent_object = this;
|
||||||
|
|
||||||
|
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<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());
|
auto result = MUST(BAN::RefPtr<Namespace>::create(NameSeg("\\"sv)));
|
||||||
|
|
||||||
AML::ParseContext context;
|
AML::ParseContext context;
|
||||||
|
context.scope = AML::NameString("\\"sv);
|
||||||
context.aml_data = aml_data;
|
context.aml_data = aml_data;
|
||||||
context.root_namespace = result.ptr();
|
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<AML::Namespace>::create(NameSeg(NAME)))));
|
||||||
|
ADD_PREDEFIED_NAMESPACE("_GPE"sv);
|
||||||
|
ADD_PREDEFIED_NAMESPACE("_PR"sv);
|
||||||
|
ADD_PREDEFIED_NAMESPACE("_SB"sv);
|
||||||
|
ADD_PREDEFIED_NAMESPACE("_SI"sv);
|
||||||
|
ADD_PREDEFIED_NAMESPACE("_TZ"sv);
|
||||||
|
#undef ADD_PREDEFIED_NAMESPACE
|
||||||
|
|
||||||
while (context.aml_data.size() > 0)
|
while (context.aml_data.size() > 0)
|
||||||
{
|
{
|
||||||
auto result = AML::parse_object(context);
|
auto result = AML::parse_object(context);
|
||||||
|
|
|
@ -86,10 +86,10 @@ 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.span(), name_string.value());
|
auto aml_object = context.root_namespace->find_object(context.scope, name_string.value());
|
||||||
if (!aml_object)
|
if (!aml_object)
|
||||||
{
|
{
|
||||||
AML_TODO("NameString not found in namespace");
|
AML_ERROR("NameString {} not found in namespace", name_string.value());
|
||||||
return ParseResult::Failure;
|
return ParseResult::Failure;
|
||||||
}
|
}
|
||||||
return ParseResult(aml_object);
|
return ParseResult(aml_object);
|
||||||
|
|
|
@ -20,33 +20,30 @@ namespace Kernel::ACPI
|
||||||
if (!name_string.has_value())
|
if (!name_string.has_value())
|
||||||
return ParseResult::Failure;
|
return ParseResult::Failure;
|
||||||
|
|
||||||
BAN::RefPtr<Scope> scope;
|
auto named_object = context.root_namespace->find_object(context.scope, name_string.value());
|
||||||
if (auto named_object = context.root_namespace->find_object(context.scope.span(), name_string.value()))
|
if (!named_object)
|
||||||
{
|
{
|
||||||
if (!named_object->is_scope())
|
AML_ERROR("Scope name {} not found in namespace", name_string.value());
|
||||||
{
|
return ParseResult::Failure;
|
||||||
AML_ERROR("Scope name already exists and is not a scope");
|
|
||||||
return ParseResult::Failure;
|
|
||||||
}
|
|
||||||
scope = static_cast<Scope*>(named_object.ptr());
|
|
||||||
}
|
}
|
||||||
else
|
if (!named_object->is_scope())
|
||||||
{
|
{
|
||||||
scope = MUST(BAN::RefPtr<Scope>::create(name_string->path.back()));
|
AML_ERROR("Scope name {} does not name a namespace", name_string.value());
|
||||||
if (!context.root_namespace->add_named_object(context.scope.span(), name_string.value(), scope))
|
return ParseResult::Failure;
|
||||||
return ParseResult::Failure;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto* scope = static_cast<Scope*>(named_object.ptr());
|
||||||
return scope->enter_context_and_parse_term_list(context, name_string.value(), scope_pkg.value());
|
return scope->enter_context_and_parse_term_list(context, name_string.value(), scope_pkg.value());
|
||||||
}
|
}
|
||||||
|
|
||||||
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.span(), name_string);
|
auto scope = outer_context.root_namespace->resolve_path(outer_context.scope, name_string);
|
||||||
if (!scope.has_value())
|
if (!scope.has_value())
|
||||||
return ParseResult::Failure;
|
return ParseResult::Failure;
|
||||||
|
|
||||||
ParseContext scope_context = outer_context;
|
ParseContext scope_context;
|
||||||
|
scope_context.root_namespace = outer_context.root_namespace;
|
||||||
scope_context.scope = scope.release_value();
|
scope_context.scope = scope.release_value();
|
||||||
scope_context.aml_data = aml_data;
|
scope_context.aml_data = aml_data;
|
||||||
while (scope_context.aml_data.size() > 0)
|
while (scope_context.aml_data.size() > 0)
|
||||||
|
@ -56,6 +53,9 @@ namespace Kernel::ACPI
|
||||||
return ParseResult::Failure;
|
return ParseResult::Failure;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (auto& name : scope_context.created_objects)
|
||||||
|
MUST(outer_context.created_objects.push_back(BAN::move(name)));
|
||||||
|
|
||||||
return ParseResult::Success;
|
return ParseResult::Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue