Kernel: Rewrite the AML conversion API

This doesn't currently make the interpreter any better, but it will make
further implementation easier to be spec (or hardware...) compliant
This commit is contained in:
2024-08-15 02:13:41 +03:00
parent 44d5c8c4b4
commit 3f5ee6f414
37 changed files with 564 additions and 416 deletions

View File

@@ -2,6 +2,7 @@
#include <BAN/StringView.h>
#include <kernel/ACPI/ACPI.h>
#include <kernel/ACPI/AML.h>
#include <kernel/ACPI/AML/Alias.h>
#include <kernel/ACPI/AML/Device.h>
#include <kernel/ACPI/AML/Field.h>
#include <kernel/ACPI/AML/Integer.h>
@@ -144,10 +145,10 @@ acpi_release_global_lock:
auto field_element = MUST(BAN::RefPtr<AML::FieldElement>::create(""_sv, register_bit_offset, register_bit_width, field_rules));
field_element->op_region = op_region;
auto result = field_element->as_integer();
auto result = field_element->convert(AML::Node::ConvInteger);
if (!result)
return {};
return result->value;
return static_cast<AML::Integer*>(result.ptr())->value;
}
bool GAS::write(uint64_t value)
@@ -168,7 +169,7 @@ acpi_release_global_lock:
auto field_element = MUST(BAN::RefPtr<AML::FieldElement>::create(""_sv, register_bit_offset, register_bit_width, field_rules));
field_element->op_region = op_region;
return field_element->store(MUST(BAN::RefPtr<AML::Integer>::create(value)));
return !!field_element->store(MUST(BAN::RefPtr<AML::Integer>::create(value)));
}
enum PM1Event : uint16_t
@@ -494,7 +495,25 @@ acpi_release_global_lock:
dwarnln("\\_S5 not found");
return;
}
auto s5_evaluated = s5_object->evaluate();
BAN::RefPtr<AML::Node> s5_evaluated = s5_object;
while (true)
{
bool done = false;
switch (s5_evaluated->type)
{
case AML::Node::Type::Alias:
s5_evaluated = static_cast<AML::Alias*>(s5_evaluated.ptr())->target;
break;
case AML::Node::Type::Name:
s5_evaluated = static_cast<AML::Name*>(s5_evaluated.ptr())->object;
break;
default:
done = true;
break;
}
if (done)
break;
}
if (!s5_evaluated)
{
dwarnln("Failed to evaluate \\_S5");
@@ -512,9 +531,9 @@ acpi_release_global_lock:
return;
}
auto slp_typa = s5_package->elements[0]->as_integer();
auto slp_typb = s5_package->elements[1]->as_integer();
if (!slp_typa || !slp_typb)
auto slp_typa_node = s5_package->elements[0]->convert(AML::Node::ConvInteger);
auto slp_typb_node = s5_package->elements[1]->convert(AML::Node::ConvInteger);
if (!slp_typa_node || !slp_typb_node)
{
dwarnln("Failed to get SLP_TYPx values");
return;
@@ -525,9 +544,12 @@ acpi_release_global_lock:
dprintln("Entering sleep state S5");
const auto slp_typa_value = static_cast<AML::Integer*>(slp_typa_node.ptr())->value;
const auto slp_typb_value = static_cast<AML::Integer*>(slp_typb_node.ptr())->value;
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 +557,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

@@ -492,13 +492,14 @@ namespace Kernel::ACPI
return MUST(BAN::RefPtr<Integer>::create(result.value()));
}
bool AML::FieldElement::store(BAN::RefPtr<AML::Node> source)
BAN::RefPtr<AML::Node> AML::FieldElement::store(BAN::RefPtr<AML::Node> source)
{
auto source_integer = source->as_integer();
ASSERT(source);
auto source_integer = source->convert(AML::Node::ConvInteger);
if (!source_integer)
{
AML_TODO("FieldElement store with non-integer source, type {}", static_cast<uint8_t>(source->type));
return false;
return {};
}
op_region->mutex.lock();
@@ -510,7 +511,9 @@ namespace Kernel::ACPI
ACPI::release_global_lock();
});
return store_internal(source_integer->value);
if (!store_internal(static_cast<AML::Integer*>(source_integer.ptr())->value))
return {};
return source_integer;
}
void AML::FieldElement::debug_print(int indent) const
@@ -626,28 +629,30 @@ namespace Kernel::ACPI
return MUST(BAN::RefPtr<Integer>::create(result.value()));
}
bool AML::IndexFieldElement::store(BAN::RefPtr<Node> source)
BAN::RefPtr<AML::Node> AML::IndexFieldElement::store(BAN::RefPtr<Node> source)
{
if (access_rules.access_attrib != FieldRules::AccessAttrib::Normal)
{
AML_TODO("FieldElement with access attribute {}", static_cast<uint8_t>(access_rules.access_attrib));
return {};
}
auto source_integer = source->as_integer();
ASSERT(source);
auto source_integer = source->convert(AML::Node::ConvInteger);
if (!source_integer)
{
AML_TODO("IndexFieldElement store with non-integer source, type {}", static_cast<uint8_t>(source->type));
return false;
return {};
}
auto access_size = determine_access_size(access_rules.access_type);
if (!access_size.has_value())
return false;
return {};
if (access_size.value() > data_element->bit_count)
{
AML_ERROR("IndexFieldElement write_field with access size {} > data element bit count {}", access_size.value(), data_element->bit_count);
return false;
return {};
}
auto read_func = [&](uint64_t byte_offset) -> BAN::Optional<uint64_t> {
@@ -657,7 +662,7 @@ namespace Kernel::ACPI
};
auto write_func = [&](uint64_t byte_offset, uint64_t value) -> bool {
if (!index_element->store_internal(byte_offset))
return false;
return {};
return data_element->store_internal(value);
};
@@ -670,10 +675,10 @@ 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))
return false;
return true;
const auto source_value = static_cast<AML::Integer*>(source_integer.ptr())->value;
if (!perform_write_general(0, bit_count, bit_offset, access_size.value(), source_value, access_rules.update_rule, read_func, write_func))
return {};
return source_integer;
}
void AML::IndexFieldElement::debug_print(int indent) const
@@ -734,8 +739,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::RefPtr<AML::Integer>();
if (!bank_value)
auto bank_value_node = bank_value_result.node() ? bank_value_result.node()->convert(AML::Node::ConvInteger) : BAN::RefPtr<AML::Node>();
if (!bank_value_node)
{
AML_ERROR("BankField BankValue is not an integer");
return ParseResult::Failure;
@@ -756,11 +761,12 @@ namespace Kernel::ACPI
if (!parse_field_element(field_context))
return ParseResult::Failure;
const auto bank_value = static_cast<AML::Integer*>(bank_value_node.ptr())->value;
for (auto& [_, element] : field_context.elements)
{
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;
NameString element_name;
MUST(element_name.path.push_back(element->name));
@@ -776,7 +782,7 @@ namespace Kernel::ACPI
return ParseResult::Success;
}
BAN::RefPtr<AML::Node> AML::BankFieldElement::evaluate()
BAN::RefPtr<AML::Integer> AML::BankFieldElement::as_integer()
{
if (access_rules.access_attrib != FieldRules::AccessAttrib::Normal)
{
@@ -812,7 +818,7 @@ namespace Kernel::ACPI
return MUST(BAN::RefPtr<Integer>::create(result.value()));
}
bool AML::BankFieldElement::store(BAN::RefPtr<AML::Node> source)
BAN::RefPtr<AML::Node> AML::BankFieldElement::store(BAN::RefPtr<AML::Node> source)
{
if (access_rules.access_attrib != FieldRules::AccessAttrib::Normal)
{
@@ -820,16 +826,17 @@ namespace Kernel::ACPI
return {};
}
auto source_integer = source->as_integer();
ASSERT(source);
auto source_integer = source->convert(AML::Node::ConvInteger);
if (!source_integer)
{
AML_TODO("BankFieldElement store with non-integer source, type {}", static_cast<uint8_t>(source->type));
return false;
return {};
}
auto access_size = determine_access_size(access_rules.access_type);
if (!access_size.has_value())
return false;
return {};
auto read_func = [&](uint64_t byte_offset) -> BAN::Optional<uint64_t> {
return perform_read(op_region->region_space, byte_offset, access_size.value());
};
@@ -852,7 +859,10 @@ 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);
const auto source_value = static_cast<AML::Integer*>(source_integer.ptr())->value;
if (!perform_write_general(op_region->region_offset, bit_count, bit_offset, access_size.value(), source_value, access_rules.update_rule, read_func, write_func))
return {};
return source_integer;
}
void AML::BankFieldElement::debug_print(int indent) const

View File

@@ -7,24 +7,6 @@
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);

View File

@@ -20,11 +20,12 @@ namespace Kernel::ACPI
struct DebugNode : AML::Node
{
DebugNode() : AML::Node(AML::Node::Type::Debug) {}
bool store(BAN::RefPtr<AML::Node> node)
BAN::RefPtr<AML::Node> convert(uint8_t) override { return {}; }
BAN::RefPtr<AML::Node> store(BAN::RefPtr<AML::Node> node)
{
node->debug_print(0);
AML_DEBUG_PRINTLN("");
return true;
return node;
}
void debug_print(int indent) const override
{
@@ -236,7 +237,7 @@ namespace Kernel::ACPI
auto osi = MUST(BAN::RefPtr<AML::Method>::create(NameSeg("_OSI"_sv), 1, false, 0));
osi->override_function = [](AML::ParseContext& context) -> BAN::RefPtr<AML::Node> {
ASSERT(context.method_args[0]);
auto arg = context.method_args[0]->evaluate();
auto arg = context.method_args[0]->convert(AML::Node::ConvString);
if (!arg || arg->type != AML::Node::Type::String)
{
AML_ERROR("Invalid _OSI argument");

View File

@@ -36,24 +36,6 @@ namespace Kernel::ACPI
uint64_t AML::Node::total_node_count = 0;
BAN::RefPtr<AML::Buffer> AML::Node::as_buffer()
{
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 {};
}
AML::ParseResult AML::parse_object(AML::ParseContext& context)
{
if (context.aml_data.size() < 1)
@@ -204,6 +186,7 @@ namespace Kernel::ACPI
return AML::Notify::parse(context);
case AML::Byte::SizeOfOp:
return AML::SizeOf::parse(context);
case AML::Byte::BreakPointOp: // TODO: support breakpoints?
case AML::Byte::NoopOp:
context.aml_data = context.aml_data.slice(1);
return ParseResult::Success;
@@ -269,6 +252,9 @@ namespace Kernel::ACPI
return ParseResult::Success;
return ParseResult(result.value());
}
if (aml_object->type == AML::Node::Type::Name)
return ParseResult(static_cast<AML::Name*>(aml_object.ptr())->object);
return ParseResult(aml_object);
}

View File

@@ -1,30 +0,0 @@
#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,7 +25,7 @@ namespace Kernel::ACPI
auto named_object = Namespace::root_namespace()->find_object(context.scope, name_string.value(), Namespace::FindMode::Normal);
if (!named_object)
{
AML_DEBUG_PRINT("Scope '{}' not found in namespace", name_string.value());
AML_PRINT("Scope '{}' not found in namespace", name_string.value());
return ParseResult::Success;
}
if (!named_object->is_scope())
@@ -69,7 +69,12 @@ namespace Kernel::ACPI
static BAN::RefPtr<AML::Integer> evaluate_or_invoke(BAN::RefPtr<AML::Node> object)
{
if (object->type != AML::Node::Type::Method)
return object->as_integer();
{
auto converted = object->convert(AML::Node::ConvInteger);
if (!converted)
return {};
return static_cast<AML::Integer*>(converted.ptr());
}
auto* method = static_cast<AML::Method*>(object.ptr());
if (method->arg_count != 0)
@@ -85,7 +90,10 @@ namespace Kernel::ACPI
return {};
}
return result.value() ? result.value()->as_integer() : BAN::RefPtr<AML::Integer>();
auto result_integer = result.value()
? result.value()->convert(AML::Node::ConvInteger)
: BAN::RefPtr<AML::Node>();
return static_cast<AML::Integer*>(result_integer.ptr());
}
bool AML::initialize_scope(BAN::RefPtr<AML::Scope> scope)

View File

@@ -6,7 +6,7 @@ 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>();
auto rhs = node ? node->convert(AML::Node::ConvString) : BAN::RefPtr<AML::Node>();
if (!rhs)
{
AML_ERROR("String logical compare RHS is not string");
@@ -27,6 +27,20 @@ namespace Kernel::ACPI::AML
return buffer;
}
BAN::RefPtr<AML::Node> String::convert(uint8_t mask)
{
if (mask & AML::Node::ConvString)
return this;
if (mask & AML::Node::ConvInteger)
{
AML_TODO("Convert String to Integer");
return {};
}
if (mask & AML::Node::ConvBuffer)
return as_buffer();
return {};
}
ParseResult String::parse(ParseContext& context)
{
ASSERT(context.aml_data.size() >= 1);