diff --git a/kernel/include/kernel/ACPI/AML/Field.h b/kernel/include/kernel/ACPI/AML/Field.h index d921b98c..c645a00f 100644 --- a/kernel/include/kernel/ACPI/AML/Field.h +++ b/kernel/include/kernel/ACPI/AML/Field.h @@ -73,6 +73,7 @@ namespace Kernel::ACPI::AML bool store_internal(uint64_t value); friend struct IndexFieldElement; + friend struct BankFieldElement; }; struct Field @@ -116,7 +117,7 @@ namespace Kernel::ACPI::AML FieldRules access_rules; BAN::RefPtr op_region; - BAN::RefPtr bank_selector; + BAN::RefPtr bank_selector; uint64_t bank_value; BankFieldElement(NameSeg name, uint64_t bit_offset, uint64_t bit_count, FieldRules access_rules) @@ -126,6 +127,9 @@ namespace Kernel::ACPI::AML , access_rules(access_rules) {} + BAN::RefPtr evaluate() override; + bool store(BAN::RefPtr source) override; + void debug_print(int indent) const override; }; diff --git a/kernel/kernel/ACPI/AML/Field.cpp b/kernel/kernel/ACPI/AML/Field.cpp index db736f68..c4530264 100644 --- a/kernel/kernel/ACPI/AML/Field.cpp +++ b/kernel/kernel/ACPI/AML/Field.cpp @@ -721,6 +721,11 @@ namespace Kernel::ACPI AML_ERROR("BankField BankSelector {} does not name a valid object", bank_selector_name.value()); return ParseResult::Failure; } + if (bank_selector->type != AML::Node::Type::FieldElement) + { + AML_TODO("BankField BankSelector {} type {2H}", static_cast(bank_selector->type)); + return ParseResult::Failure; + } auto temp_aml_data = context.aml_data; context.aml_data = field_pkg; @@ -754,7 +759,7 @@ namespace Kernel::ACPI for (auto& [_, element] : field_context.elements) { element->op_region = static_cast(op_region.ptr()); - element->bank_selector = bank_selector; + element->bank_selector = static_cast(bank_selector.ptr()); element->bank_value = bank_value.value(); NameString element_name; @@ -771,6 +776,85 @@ namespace Kernel::ACPI return ParseResult::Success; } + BAN::RefPtr AML::BankFieldElement::evaluate() + { + if (access_rules.access_attrib != FieldRules::AccessAttrib::Normal) + { + AML_TODO("BankFieldElement with access attribute {}", static_cast(access_rules.access_attrib)); + return {}; + } + + auto access_size = determine_access_size(access_rules.access_type); + if (!access_size.has_value()) + return {}; + auto read_func = [&](uint64_t byte_offset) -> BAN::Optional { + return perform_read(op_region->region_space, byte_offset, access_size.value()); + }; + + bank_selector->op_region->mutex.lock(); + if (access_rules.lock_rule == FieldRules::LockRule::Lock) + ACPI::acquire_global_lock(); + BAN::ScopeGuard unlock_guard([&] { + bank_selector->op_region->mutex.unlock(); + if (access_rules.lock_rule == FieldRules::LockRule::Lock) + ACPI::release_global_lock(); + }); + + if (!bank_selector->store_internal(bank_value)) + { + AML_ERROR("BankFieldElement failed to store BankValue"); + return {}; + } + + auto result = perform_read_general(op_region->region_offset, bit_count, bit_offset, access_size.value(), read_func); + if (!result.has_value()) + return {}; + return MUST(BAN::RefPtr::create(result.value())); + } + + bool AML::BankFieldElement::store(BAN::RefPtr source) + { + if (access_rules.access_attrib != FieldRules::AccessAttrib::Normal) + { + AML_TODO("BankFieldElement with access attribute {}", static_cast(access_rules.access_attrib)); + return {}; + } + + auto source_integer = source->as_integer(); + if (!source_integer.has_value()) + { + AML_TODO("BankFieldElement store with non-integer source, type {}", static_cast(source->type)); + return false; + } + + auto access_size = determine_access_size(access_rules.access_type); + if (!access_size.has_value()) + return false; + auto read_func = [&](uint64_t byte_offset) -> BAN::Optional { + return perform_read(op_region->region_space, byte_offset, access_size.value()); + }; + auto write_func = [&](uint64_t byte_offset, uint64_t value) -> bool { + return perform_write(op_region->region_space, byte_offset, access_size.value(), value); + }; + + bank_selector->op_region->mutex.lock(); + if (access_rules.lock_rule == FieldRules::LockRule::Lock) + ACPI::acquire_global_lock(); + BAN::ScopeGuard unlock_guard([&] { + bank_selector->op_region->mutex.unlock(); + if (access_rules.lock_rule == FieldRules::LockRule::Lock) + ACPI::release_global_lock(); + }); + + if (!bank_selector->store_internal(bank_value)) + { + AML_ERROR("BankFieldElement failed to store BankValue"); + 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); + } + void AML::BankFieldElement::debug_print(int indent) const { AML_DEBUG_PRINT_INDENT(indent);