forked from Bananymous/banan-os
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:
@@ -35,7 +35,7 @@ namespace Kernel::ACPI
|
||||
|
||||
auto dsdt = s_instance->get_header("DSDT", 0);
|
||||
ASSERT(dsdt);
|
||||
s_instance->m_namespace = AMLParser::parse_table(*dsdt);
|
||||
s_instance->m_namespace = AML::initialize_namespace(*dsdt);
|
||||
|
||||
#if ARCH(x86_64)
|
||||
lai_create_namespace();
|
||||
|
||||
@@ -6,10 +6,7 @@
|
||||
namespace Kernel::ACPI
|
||||
{
|
||||
|
||||
AMLParser::AMLParser() = default;
|
||||
AMLParser::~AMLParser() = default;
|
||||
|
||||
BAN::RefPtr<AML::Namespace> AMLParser::parse_table(const SDTHeader& header)
|
||||
BAN::RefPtr<AML::Namespace> AML::initialize_namespace(const SDTHeader& header)
|
||||
{
|
||||
dprintln("Parsing {}, {} bytes of AML", header, header.length);
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include <kernel/ACPI/AML/Field.h>
|
||||
#include <kernel/ACPI/AML/Integer.h>
|
||||
|
||||
namespace Kernel::ACPI
|
||||
{
|
||||
@@ -93,7 +94,7 @@ namespace Kernel::ACPI
|
||||
if (!name_string.has_value())
|
||||
return ParseResult::Failure;
|
||||
|
||||
auto op_region = context.root_namespace->find_object(context.scope, name_string.value());
|
||||
auto op_region = Namespace::root_namespace()->find_object(context.scope, name_string.value());
|
||||
if (!op_region || op_region->type != AML::Node::Type::OpRegion)
|
||||
{
|
||||
AML_ERROR("FieldOp: {} does not name a valid OpRegion", name_string.value());
|
||||
@@ -121,7 +122,7 @@ namespace Kernel::ACPI
|
||||
|
||||
NameString element_name;
|
||||
MUST(element_name.path.push_back(element->name));
|
||||
if (!context.root_namespace->add_named_object(context, element_name, element))
|
||||
if (!Namespace::root_namespace()->add_named_object(context, element_name, element))
|
||||
return ParseResult::Failure;
|
||||
|
||||
#if AML_DEBUG_LEVEL >= 2
|
||||
@@ -133,6 +134,72 @@ namespace Kernel::ACPI
|
||||
return ParseResult::Success;
|
||||
}
|
||||
|
||||
BAN::RefPtr<AML::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
|
||||
{
|
||||
AML_DEBUG_PRINT_INDENT(indent);
|
||||
@@ -158,7 +225,7 @@ namespace Kernel::ACPI
|
||||
auto index_field_element_name = NameString::parse(field_pkg);
|
||||
if (!index_field_element_name.has_value())
|
||||
return ParseResult::Failure;
|
||||
auto index_field_element = context.root_namespace->find_object(context.scope, index_field_element_name.value());
|
||||
auto index_field_element = Namespace::root_namespace()->find_object(context.scope, index_field_element_name.value());
|
||||
if (!index_field_element || index_field_element->type != AML::Node::Type::FieldElement)
|
||||
{
|
||||
AML_ERROR("IndexField IndexName does not name a valid FieldElement");
|
||||
@@ -168,7 +235,7 @@ namespace Kernel::ACPI
|
||||
auto data_field_element_name = NameString::parse(field_pkg);
|
||||
if (!data_field_element_name.has_value())
|
||||
return ParseResult::Failure;
|
||||
auto data_field_element = context.root_namespace->find_object(context.scope, data_field_element_name.value());
|
||||
auto data_field_element = Namespace::root_namespace()->find_object(context.scope, data_field_element_name.value());
|
||||
if (!data_field_element || data_field_element->type != AML::Node::Type::FieldElement)
|
||||
{
|
||||
AML_ERROR("IndexField DataName does not name a valid FieldElement");
|
||||
@@ -197,7 +264,7 @@ namespace Kernel::ACPI
|
||||
|
||||
NameString element_name;
|
||||
MUST(element_name.path.push_back(element->name));
|
||||
if (!context.root_namespace->add_named_object(context, element_name, element))
|
||||
if (!Namespace::root_namespace()->add_named_object(context, element_name, element))
|
||||
return ParseResult::Failure;
|
||||
|
||||
#if AML_DEBUG_LEVEL >= 2
|
||||
|
||||
@@ -19,7 +19,7 @@ namespace Kernel::ACPI
|
||||
return ParseResult::Failure;
|
||||
|
||||
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;
|
||||
|
||||
#if AML_DEBUG_LEVEL >= 2
|
||||
|
||||
@@ -5,6 +5,14 @@
|
||||
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)
|
||||
{
|
||||
// Base must be non-empty absolute path
|
||||
@@ -143,6 +151,8 @@ namespace Kernel::ACPI
|
||||
return false;
|
||||
}
|
||||
|
||||
object->parent = parent_scope;
|
||||
|
||||
MUST(parent_scope->objects.insert(object->name, object));
|
||||
|
||||
auto canonical_scope = resolve_path(parse_context.scope, object_path);
|
||||
@@ -159,66 +169,39 @@ namespace Kernel::ACPI
|
||||
|
||||
bool AML::Namespace::remove_named_object(const AML::NameString& absolute_path)
|
||||
{
|
||||
auto canonical_path = resolve_path({}, absolute_path);
|
||||
if (!canonical_path.has_value())
|
||||
auto object = find_object({}, absolute_path);
|
||||
if (!object)
|
||||
{
|
||||
AML_ERROR("Failed to resolve path");
|
||||
AML_ERROR("Object {} not found", absolute_path);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (canonical_path->path.empty())
|
||||
if (object.ptr() == this)
|
||||
{
|
||||
AML_ERROR("Trying to remove root object");
|
||||
return false;
|
||||
}
|
||||
|
||||
BAN::RefPtr<NamedObject> parent_object = this;
|
||||
auto parent = object->parent;
|
||||
ASSERT(parent->is_scope());
|
||||
|
||||
for (size_t i = 0; i < canonical_path->path.size() - 1; i++)
|
||||
{
|
||||
if (!parent_object->is_scope())
|
||||
{
|
||||
AML_ERROR("Parent object is not a scope");
|
||||
return false;
|
||||
}
|
||||
|
||||
auto* parent_scope = static_cast<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());
|
||||
auto* parent_scope = static_cast<Scope*>(parent.ptr());
|
||||
parent_scope->objects.remove(object->name);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
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;
|
||||
context.scope = AML::NameString("\\"sv);
|
||||
context.aml_data = aml_data;
|
||||
context.root_namespace = result.ptr();
|
||||
|
||||
// Add predefined namespaces
|
||||
#define ADD_PREDEFIED_NAMESPACE(NAME) \
|
||||
ASSERT(result->add_named_object(context, AML::NameString("\\" NAME), MUST(BAN::RefPtr<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("_PR"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/Bytes.h>
|
||||
#include <kernel/ACPI/AML/Device.h>
|
||||
#include <kernel/ACPI/AML/Expression.h>
|
||||
#include <kernel/ACPI/AML/Field.h>
|
||||
#include <kernel/ACPI/AML/IfElse.h>
|
||||
#include <kernel/ACPI/AML/Integer.h>
|
||||
#include <kernel/ACPI/AML/Method.h>
|
||||
#include <kernel/ACPI/AML/Mutex.h>
|
||||
@@ -11,6 +13,7 @@
|
||||
#include <kernel/ACPI/AML/ParseContext.h>
|
||||
#include <kernel/ACPI/AML/Processor.h>
|
||||
#include <kernel/ACPI/AML/Region.h>
|
||||
#include <kernel/ACPI/AML/Store.h>
|
||||
#include <kernel/ACPI/AML/String.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::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)
|
||||
{
|
||||
if (context.aml_data.size() < 1)
|
||||
@@ -64,6 +79,53 @@ namespace Kernel::ACPI
|
||||
return AML::Integer::parse(context.aml_data);
|
||||
case AML::Byte::StringPrefix:
|
||||
return AML::String::parse(context);
|
||||
case AML::Byte::Arg0:
|
||||
case AML::Byte::Arg1:
|
||||
case AML::Byte::Arg2:
|
||||
case AML::Byte::Arg3:
|
||||
case AML::Byte::Arg4:
|
||||
case AML::Byte::Arg5:
|
||||
case AML::Byte::Arg6:
|
||||
{
|
||||
uint8_t index = context.aml_data[0] - static_cast<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:
|
||||
return AML::Name::parse(context);
|
||||
case AML::Byte::PackageOp:
|
||||
@@ -74,6 +136,19 @@ namespace Kernel::ACPI
|
||||
return AML::Buffer::parse(context);
|
||||
case AML::Byte::ScopeOp:
|
||||
return AML::Scope::parse(context);
|
||||
case AML::Byte::IfOp:
|
||||
return AML::IfElse::parse(context);
|
||||
case AML::Byte::StoreOp:
|
||||
return AML::Store::parse(context);
|
||||
case AML::Byte::ReturnOp:
|
||||
{
|
||||
context.aml_data = context.aml_data.slice(1);
|
||||
auto result = AML::parse_object(context);
|
||||
if (result.success())
|
||||
return ParseResult(ParseResult::Result::Returned, result.node());
|
||||
AML_ERROR("Failed to parse return value for method {}", context.scope);
|
||||
return ParseResult::Failure;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -86,12 +161,36 @@ namespace Kernel::ACPI
|
||||
auto name_string = AML::NameString::parse(context.aml_data);
|
||||
if (!name_string.has_value())
|
||||
return ParseResult::Failure;
|
||||
auto aml_object = context.root_namespace->find_object(context.scope, name_string.value());
|
||||
auto aml_object = Namespace::root_namespace()->find_object(context.scope, name_string.value());
|
||||
if (!aml_object)
|
||||
{
|
||||
AML_ERROR("NameString {} not found in namespace", name_string.value());
|
||||
return ParseResult::Failure;
|
||||
}
|
||||
if (aml_object->type == AML::Node::Type::Method)
|
||||
{
|
||||
auto* method = static_cast<AML::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);
|
||||
}
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ namespace Kernel::ACPI
|
||||
if (!name_string.has_value())
|
||||
return ParseResult::Failure;
|
||||
|
||||
auto named_object = context.root_namespace->find_object(context.scope, name_string.value());
|
||||
auto named_object = Namespace::root_namespace()->find_object(context.scope, name_string.value());
|
||||
if (!named_object)
|
||||
{
|
||||
AML_ERROR("Scope name {} not found in namespace", name_string.value());
|
||||
@@ -38,17 +38,22 @@ namespace Kernel::ACPI
|
||||
|
||||
AML::ParseResult AML::Scope::enter_context_and_parse_term_list(ParseContext& outer_context, const AML::NameString& name_string, BAN::ConstByteSpan aml_data)
|
||||
{
|
||||
auto scope = outer_context.root_namespace->resolve_path(outer_context.scope, name_string);
|
||||
if (!scope.has_value())
|
||||
auto resolved_scope = Namespace::root_namespace()->resolve_path(outer_context.scope, name_string);
|
||||
if (!resolved_scope.has_value())
|
||||
return ParseResult::Failure;
|
||||
|
||||
ParseContext scope_context;
|
||||
scope_context.root_namespace = outer_context.root_namespace;
|
||||
scope_context.scope = scope.release_value();
|
||||
scope_context.scope = resolved_scope.release_value();
|
||||
scope_context.aml_data = aml_data;
|
||||
scope_context.method_args = outer_context.method_args;
|
||||
while (scope_context.aml_data.size() > 0)
|
||||
{
|
||||
auto object_result = AML::parse_object(scope_context);
|
||||
if (object_result.returned())
|
||||
{
|
||||
AML_ERROR("Unexpected return from scope {}", scope_context.scope);
|
||||
return ParseResult::Failure;
|
||||
}
|
||||
if (!object_result.success())
|
||||
return ParseResult::Failure;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user