Kernel: Fix and cleanup a lot of AML code

Node now have APIs to convert them to buffer, integer and string. This
allows possibility to handle methods that need explicitly use one of the
overloads instead of integer.

This patch also adds handling of DebugOp. This is used quite heavily in
uACPIs test suite.
This commit is contained in:
2024-08-13 22:14:14 +03:00
parent dd79db6383
commit ec4cfdee23
29 changed files with 415 additions and 149 deletions

View File

@@ -145,9 +145,9 @@ acpi_release_global_lock:
field_element->op_region = op_region;
auto result = field_element->as_integer();
if (!result.has_value())
if (!result)
return {};
return result.value();
return result->value;
}
bool GAS::write(uint64_t value)
@@ -514,7 +514,7 @@ acpi_release_global_lock:
auto slp_typa = s5_package->elements[0]->as_integer();
auto slp_typb = s5_package->elements[1]->as_integer();
if (!slp_typa.has_value() || !slp_typb.has_value())
if (!slp_typa || !slp_typb)
{
dwarnln("Failed to get SLP_TYPx values");
return;
@@ -527,7 +527,7 @@ acpi_release_global_lock:
uint16_t pm1a_data = IO::inw(fadt().pm1a_cnt_blk);
pm1a_data &= ~(PM1_CNT_SLP_TYP_MASK << PM1_CNT_SLP_TYP_SHIFT);
pm1a_data |= (slp_typa.value() & PM1_CNT_SLP_TYP_MASK) << PM1_CNT_SLP_TYP_SHIFT;
pm1a_data |= (slp_typa->value & PM1_CNT_SLP_TYP_MASK) << PM1_CNT_SLP_TYP_SHIFT;
pm1a_data |= PM1_CNT_SLP_EN;
IO::outw(fadt().pm1a_cnt_blk, pm1a_data);
@@ -535,7 +535,7 @@ acpi_release_global_lock:
{
uint16_t pm1b_data = IO::inw(fadt().pm1b_cnt_blk);
pm1b_data &= ~(PM1_CNT_SLP_TYP_MASK << PM1_CNT_SLP_TYP_SHIFT);
pm1b_data |= (slp_typb.value() & PM1_CNT_SLP_TYP_MASK) << PM1_CNT_SLP_TYP_SHIFT;
pm1b_data |= (slp_typb->value & PM1_CNT_SLP_TYP_MASK) << PM1_CNT_SLP_TYP_SHIFT;
pm1b_data |= PM1_CNT_SLP_EN;
IO::outw(fadt().pm1b_cnt_blk, pm1b_data);
}

View File

@@ -479,7 +479,7 @@ namespace Kernel::ACPI
return perform_write_general(op_region->region_offset, bit_count, bit_offset, access_size.value(), value, access_rules.update_rule, read_func, write_func);
}
BAN::RefPtr<AML::Node> AML::FieldElement::evaluate()
BAN::RefPtr<AML::Integer> AML::FieldElement::as_integer()
{
op_region->mutex.lock();
BAN::ScopeGuard unlock_guard([&] {
@@ -495,7 +495,7 @@ namespace Kernel::ACPI
bool AML::FieldElement::store(BAN::RefPtr<AML::Node> source)
{
auto source_integer = source->as_integer();
if (!source_integer.has_value())
if (!source_integer)
{
AML_TODO("FieldElement store with non-integer source, type {}", static_cast<uint8_t>(source->type));
return false;
@@ -510,7 +510,7 @@ namespace Kernel::ACPI
ACPI::release_global_lock();
});
return store_internal(source_integer.value());
return store_internal(source_integer->value);
}
void AML::FieldElement::debug_print(int indent) const
@@ -590,7 +590,7 @@ namespace Kernel::ACPI
return AML::ParseResult::Success;
}
BAN::RefPtr<AML::Node> AML::IndexFieldElement::evaluate()
BAN::RefPtr<AML::Integer> AML::IndexFieldElement::as_integer()
{
if (access_rules.access_attrib != FieldRules::AccessAttrib::Normal)
{
@@ -634,7 +634,7 @@ namespace Kernel::ACPI
return {};
}
auto source_integer = source->as_integer();
if (!source_integer.has_value())
if (!source_integer)
{
AML_TODO("IndexFieldElement store with non-integer source, type {}", static_cast<uint8_t>(source->type));
return false;
@@ -670,7 +670,7 @@ namespace Kernel::ACPI
ACPI::release_global_lock();
});
if (!perform_write_general(0, bit_count, bit_offset, access_size.value(), source_integer.value(), access_rules.update_rule, read_func, write_func))
if (!perform_write_general(0, bit_count, bit_offset, access_size.value(), source_integer->value, access_rules.update_rule, read_func, write_func))
return false;
return true;
@@ -734,8 +734,8 @@ namespace Kernel::ACPI
context.aml_data = temp_aml_data;
if (!bank_value_result.success())
return ParseResult::Failure;
auto bank_value = bank_value_result.node() ? bank_value_result.node()->as_integer() : BAN::Optional<uint64_t>();
if (!bank_value.has_value())
auto bank_value = bank_value_result.node() ? bank_value_result.node()->as_integer() : BAN::RefPtr<AML::Integer>();
if (!bank_value)
{
AML_ERROR("BankField BankValue is not an integer");
return ParseResult::Failure;
@@ -760,7 +760,7 @@ namespace Kernel::ACPI
{
element->op_region = static_cast<OpRegion*>(op_region.ptr());
element->bank_selector = static_cast<FieldElement*>(bank_selector.ptr());
element->bank_value = bank_value.value();
element->bank_value = bank_value->value;
NameString element_name;
MUST(element_name.path.push_back(element->name));
@@ -821,7 +821,7 @@ namespace Kernel::ACPI
}
auto source_integer = source->as_integer();
if (!source_integer.has_value())
if (!source_integer)
{
AML_TODO("BankFieldElement store with non-integer source, type {}", static_cast<uint8_t>(source->type));
return false;
@@ -852,7 +852,7 @@ namespace Kernel::ACPI
return {};
}
return perform_write_general(op_region->region_offset, bit_count, bit_offset, access_size.value(), source_integer.value(), access_rules.update_rule, read_func, write_func);
return perform_write_general(op_region->region_offset, bit_count, bit_offset, access_size.value(), source_integer->value, access_rules.update_rule, read_func, write_func);
}
void AML::BankFieldElement::debug_print(int indent) const

View File

@@ -1,9 +1,30 @@
#include <kernel/ACPI/AML/Buffer.h>
#include <kernel/ACPI/AML/Integer.h>
#include <kernel/ACPI/AML/NamedObject.h>
#include <kernel/ACPI/AML/ParseContext.h>
#include <kernel/ACPI/AML/String.h>
namespace Kernel::ACPI
{
BAN::RefPtr<AML::Buffer> AML::Name::as_buffer()
{
ASSERT(object);
return object->as_buffer();
}
BAN::RefPtr<AML::Integer> AML::Name::as_integer()
{
ASSERT(object);
return object->as_integer();
}
BAN::RefPtr<AML::String> AML::Name::as_string()
{
ASSERT(object);
return object->as_string();
}
AML::ParseResult AML::Name::parse(ParseContext& context)
{
ASSERT(context.aml_data.size() >= 1);
@@ -20,7 +41,7 @@ namespace Kernel::ACPI
auto name = MUST(BAN::RefPtr<Name>::create(name_string.value().path.back(), object.node()));
if (!Namespace::root_namespace()->add_named_object(context, name_string.value(), name))
return ParseResult::Failure;
return ParseResult::Success;
#if AML_DEBUG_LEVEL >= 2
name->debug_print(0);

View File

@@ -17,6 +17,24 @@ namespace Kernel::ACPI
BAN::RefPtr<AML::Integer> AML::Integer::Constants::One;
BAN::RefPtr<AML::Integer> AML::Integer::Constants::Ones;
struct DebugNode : AML::Node
{
DebugNode() : AML::Node(AML::Node::Type::Debug) {}
bool store(BAN::RefPtr<AML::Node> node)
{
node->debug_print(0);
AML_DEBUG_PRINTLN("");
return true;
}
void debug_print(int indent) const override
{
AML_DEBUG_PRINT_INDENT(indent);
AML_DEBUG_PRINT("DEBUG");
}
};
BAN::RefPtr<AML::Node> AML::Namespace::debug_node;
BAN::RefPtr<AML::Namespace> AML::Namespace::root_namespace()
{
ASSERT(s_root_namespace);
@@ -147,7 +165,7 @@ namespace Kernel::ACPI
if (m_objects.contains(canonical_path.value()))
{
AML_ERROR("Object '{}' already exists", canonical_path.value());
AML_PRINT("Object '{}' already exists", canonical_path.value());
return false;
}
@@ -194,6 +212,9 @@ namespace Kernel::ACPI
s_root_namespace = MUST(BAN::RefPtr<Namespace>::create(NameSeg("\\"_sv)));
s_root_namespace->scope = AML::NameString("\\"_sv);
ASSERT(!Namespace::debug_node);
Namespace::debug_node = MUST(BAN::RefPtr<DebugNode>::create());
Integer::Constants::Zero = MUST(BAN::RefPtr<Integer>::create(0, true));
Integer::Constants::One = MUST(BAN::RefPtr<Integer>::create(1, true));
Integer::Constants::Ones = MUST(BAN::RefPtr<Integer>::create(0xFFFFFFFFFFFFFFFF, true));

View File

@@ -33,15 +33,21 @@ namespace Kernel::ACPI
uint64_t AML::Node::total_node_count = 0;
BAN::Optional<uint64_t> AML::Node::as_integer()
BAN::RefPtr<AML::Buffer> AML::Node::as_buffer()
{
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*>(evaluated.ptr())->value;
AML_TODO("Node type {} to buffer", static_cast<uint32_t>(type));
return {};
}
BAN::RefPtr<AML::Integer> AML::Node::as_integer()
{
AML_TODO("Node type {} to integer", static_cast<uint32_t>(type));
return {};
}
BAN::RefPtr<AML::String> AML::Node::as_string()
{
AML_TODO("Node type {} to string", static_cast<uint32_t>(type));
return {};
}
@@ -83,6 +89,9 @@ namespace Kernel::ACPI
return AML::Reference::parse(context);
case AML::ExtOp::SleepOp:
return AML::Sleep::parse(context);
case AML::ExtOp::DebugOp:
context.aml_data = context.aml_data.slice(2);
return ParseResult(AML::Namespace::debug_node);
default:
break;
}

View File

@@ -0,0 +1,30 @@
#include <kernel/ACPI/AML/Buffer.h>
#include <kernel/ACPI/AML/Integer.h>
#include <kernel/ACPI/AML/Register.h>
#include <kernel/ACPI/AML/String.h>
namespace Kernel::ACPI::AML
{
BAN::RefPtr<AML::Buffer> Register::as_buffer()
{
if (value)
return value->as_buffer();
return {};
}
BAN::RefPtr<AML::Integer> Register::as_integer()
{
if (value)
return value->as_integer();
return {};
}
BAN::RefPtr<AML::String> Register::as_string()
{
if (value)
return value->as_string();
return {};
}
}

View File

@@ -25,8 +25,8 @@ namespace Kernel::ACPI
auto named_object = Namespace::root_namespace()->find_object(context.scope, name_string.value(), Namespace::FindMode::Normal);
if (!named_object)
{
AML_ERROR("Scope '{}' not found in namespace", name_string.value());
return ParseResult::Failure;
AML_DEBUG_PRINT("Scope '{}' not found in namespace", name_string.value());
return ParseResult::Success;
}
if (!named_object->is_scope())
{
@@ -66,7 +66,7 @@ namespace Kernel::ACPI
return ParseResult::Success;
}
static BAN::Optional<uint64_t> evaluate_or_invoke(BAN::RefPtr<AML::Node> object)
static BAN::RefPtr<AML::Integer> evaluate_or_invoke(BAN::RefPtr<AML::Node> object)
{
if (object->type != AML::Node::Type::Method)
return object->as_integer();
@@ -85,7 +85,7 @@ namespace Kernel::ACPI
return {};
}
return result.value() ? result.value()->as_integer() : BAN::Optional<uint64_t>();
return result.value() ? result.value()->as_integer() : BAN::RefPtr<AML::Integer>();
}
bool AML::initialize_scope(BAN::RefPtr<AML::Scope> scope)
@@ -138,14 +138,14 @@ namespace Kernel::ACPI
if (auto sta = Namespace::root_namespace()->find_object(scope->scope, AML::NameString("_STA"_sv), Namespace::FindMode::ForceAbsolute))
{
auto result = evaluate_or_invoke(sta);
if (!result.has_value())
if (!result)
{
AML_ERROR("Failed to evaluate {}._STA, return value could not be resolved to integer", scope->scope);
return false;
}
run_ini = (result.value() & 0x01);
init_children = run_ini || (result.value() & 0x02);
run_ini = (result->value & 0x01);
init_children = run_ini || (result->value & 0x02);
}
if (run_ini)

View File

@@ -0,0 +1,58 @@
#include <kernel/ACPI/AML/Buffer.h>
#include <kernel/ACPI/AML/String.h>
namespace Kernel::ACPI::AML
{
BAN::Optional<bool> String::logical_compare(BAN::RefPtr<AML::Node> node, AML::Byte binaryop)
{
auto rhs = node ? node->as_string() : BAN::RefPtr<AML::String>();
if (!rhs)
{
AML_ERROR("String logical compare RHS is not string");
return {};
}
(void)binaryop;
AML_TODO("Logical compare string");
return {};
}
BAN::RefPtr<AML::Buffer> String::as_buffer()
{
auto buffer = MUST(BAN::RefPtr<AML::Buffer>::create());
MUST(buffer->buffer.resize(string.size()));
for (size_t i = 0; i < string.size(); i++)
buffer->buffer[i] = string[i];
return buffer;
}
ParseResult String::parse(ParseContext& context)
{
ASSERT(context.aml_data.size() >= 1);
ASSERT(static_cast<AML::Byte>(context.aml_data[0]) == AML::Byte::StringPrefix);
context.aml_data = context.aml_data.slice(1);
BAN::Vector<uint8_t> string;
while (context.aml_data.size() > 0)
{
if (context.aml_data[0] == 0x00)
break;
MUST(string.push_back(context.aml_data[0]));
context.aml_data = context.aml_data.slice(1);
}
if (context.aml_data.size() == 0)
return ParseResult::Failure;
if (context.aml_data[0] != 0x00)
return ParseResult::Failure;
context.aml_data = context.aml_data.slice(1);
auto string_node = MUST(BAN::RefPtr<String>::create());
string_node->string = BAN::move(string);
return ParseResult(string_node);
}
}