diff --git a/kernel/include/kernel/ACPI/AML/Event.h b/kernel/include/kernel/ACPI/AML/Event.h new file mode 100644 index 00000000..d5411d09 --- /dev/null +++ b/kernel/include/kernel/ACPI/AML/Event.h @@ -0,0 +1,143 @@ +#pragma once + +#include +#include +#include +#include +#include +#include + +namespace Kernel::ACPI::AML +{ + + struct Event : public AML::NamedObject + { + BAN::Atomic signal_count { 0 }; + ThreadBlocker thread_blocker; + + Event(NameSeg name) + : NamedObject(Node::Type::Event, name) + {} + + static ParseResult parse(ParseContext& context) + { + ASSERT(context.aml_data.size() >= 2); + ASSERT(static_cast(context.aml_data[0]) == AML::Byte::ExtOpPrefix); + + const auto ext_op = static_cast(context.aml_data[1]); + switch (ext_op) + { + case AML::ExtOp::EventOp: + return parse_event(context); + case AML::ExtOp::ResetOp: + case AML::ExtOp::SignalOp: + case AML::ExtOp::WaitOp: + break; + default: + ASSERT_NOT_REACHED(); + } + + context.aml_data = context.aml_data.slice(2); + + auto event_result = parse_object(context); + if (!event_result.success()) + return ParseResult::Failure; + + auto general_node = event_result.node() ? event_result.node()->evaluate() : BAN::RefPtr(); + if (!general_node || general_node->type != Node::Type::Event) + { + AML_ERROR("Release, Wait or Signal does not name an event"); + return ParseResult::Failure; + } + + auto* event_node = static_cast(general_node.ptr()); + + if (ext_op == AML::ExtOp::WaitOp) + { + auto timeout_result = parse_object(context); + if (!timeout_result.success()) + return ParseResult::Failure; + + auto timeout = timeout_result.node() ? timeout_result.node()->as_integer() : BAN::RefPtr(); + if (!timeout) + { + AML_ERROR("Wait timeout does not evaluate to integer"); + return ParseResult::Failure; + } + + const uint64_t start_ms = SystemTimer::get().ms_since_boot(); + while (true) + { + auto expected = event_node->signal_count.load(); + while (true) + { + if (expected == 0) + break; + if (event_node->signal_count.compare_exchange(expected, expected - 1)) + return ParseResult(Integer::Constants::Zero); + } + + if (timeout->value >= 0xFFFF) + event_node->thread_blocker.block_indefinite(); + else + { + const uint64_t current_ms = SystemTimer::get().ms_since_boot(); + if (current_ms >= start_ms + timeout->value) + return ParseResult(Integer::Constants::Ones); + event_node->thread_blocker.block_with_timeout_ms(start_ms + timeout->value - current_ms); + } + } + + ASSERT_NOT_REACHED(); + } + + switch (ext_op) + { + case AML::ExtOp::ResetOp: + event_node->signal_count = 0; + break; + case AML::ExtOp::SignalOp: + event_node->signal_count++; + event_node->thread_blocker.unblock(); + break; + default: + ASSERT_NOT_REACHED(); + } + + return ParseResult::Success; + } + + virtual void debug_print(int indent) const override + { + AML_DEBUG_PRINT_INDENT(indent); + AML_DEBUG_PRINT("Event "); + name.debug_print(); + AML_DEBUG_PRINT(" (Signals: {})", signal_count.load()); + } + + private: + static ParseResult parse_event(ParseContext& context) + { + ASSERT(context.aml_data.size() >= 2); + ASSERT(static_cast(context.aml_data[0]) == AML::Byte::ExtOpPrefix); + ASSERT(static_cast(context.aml_data[1]) == AML::ExtOp::EventOp); + context.aml_data = context.aml_data.slice(2); + + auto name_string = NameString::parse(context.aml_data); + if (!name_string.has_value()) + return ParseResult::Failure; + + auto event = MUST(BAN::RefPtr::create(name_string->path.back())); + if (!Namespace::root_namespace()->add_named_object(context, name_string.value(), event)) + return ParseResult::Success; + +#if AML_DEBUG_LEVEL >= 2 + event->debug_print(0); + AML_DEBUG_PRINTLN(""); +#endif + + return ParseResult::Success; + } + }; + +} diff --git a/kernel/include/kernel/ACPI/AML/Node.h b/kernel/include/kernel/ACPI/AML/Node.h index df451474..c568a623 100644 --- a/kernel/include/kernel/ACPI/AML/Node.h +++ b/kernel/include/kernel/ACPI/AML/Node.h @@ -25,6 +25,7 @@ namespace Kernel::ACPI::AML BufferField, Debug, Device, + Event, FieldElement, IndexFieldElement, Integer, diff --git a/kernel/kernel/ACPI/AML/Node.cpp b/kernel/kernel/ACPI/AML/Node.cpp index fb2854ef..729fd62f 100644 --- a/kernel/kernel/ACPI/AML/Node.cpp +++ b/kernel/kernel/ACPI/AML/Node.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -76,6 +77,11 @@ namespace Kernel::ACPI return AML::OpRegion::parse(context); case AML::ExtOp::DeviceOp: return AML::Device::parse(context); + case AML::ExtOp::EventOp: + case AML::ExtOp::ResetOp: + case AML::ExtOp::SignalOp: + case AML::ExtOp::WaitOp: + return AML::Event::parse(context); case AML::ExtOp::MutexOp: case AML::ExtOp::AcquireOp: case AML::ExtOp::ReleaseOp: