From 869f4011a1be8f6286f0af9eec0dd0070b57684f Mon Sep 17 00:00:00 2001 From: Bananymous Date: Thu, 12 Dec 2024 07:03:09 +0200 Subject: [PATCH] Kernel: Replace the old AML interpreter by a new, better one The old AML interpreter was trash and did not follow value/reference semantics at all. It was also super slow, one of my machines taking over 7 seconds to parse ACPI namespace and call _INI and _STA. --- kernel/CMakeLists.txt | 8 +- kernel/include/kernel/ACPI/ACPI.h | 20 +- kernel/include/kernel/ACPI/AML.h | 11 - kernel/include/kernel/ACPI/AML/Alias.h | 48 - kernel/include/kernel/ACPI/AML/Buffer.h | 312 -- kernel/include/kernel/ACPI/AML/Bytes.h | 22 +- kernel/include/kernel/ACPI/AML/Concat.h | 124 - kernel/include/kernel/ACPI/AML/Conversion.h | 124 - kernel/include/kernel/ACPI/AML/CopyObject.h | 65 - kernel/include/kernel/ACPI/AML/Device.h | 59 - kernel/include/kernel/ACPI/AML/Event.h | 148 - kernel/include/kernel/ACPI/AML/Expression.h | 283 -- kernel/include/kernel/ACPI/AML/Field.h | 199 - kernel/include/kernel/ACPI/AML/IfElse.h | 65 - kernel/include/kernel/ACPI/AML/Index.h | 126 - kernel/include/kernel/ACPI/AML/Integer.h | 39 - kernel/include/kernel/ACPI/AML/Method.h | 182 - kernel/include/kernel/ACPI/AML/Mutex.h | 170 - kernel/include/kernel/ACPI/AML/NamedObject.h | 44 - kernel/include/kernel/ACPI/AML/Names.h | 244 -- kernel/include/kernel/ACPI/AML/Namespace.h | 96 +- kernel/include/kernel/ACPI/AML/Node.h | 476 ++- kernel/include/kernel/ACPI/AML/Notify.h | 67 - kernel/include/kernel/ACPI/AML/ObjectType.h | 107 - kernel/include/kernel/ACPI/AML/OpRegion.h | 16 + kernel/include/kernel/ACPI/AML/Package.h | 168 - kernel/include/kernel/ACPI/AML/ParseContext.h | 30 - kernel/include/kernel/ACPI/AML/Pkg.h | 51 - .../include/kernel/ACPI/AML/PowerResource.h | 70 - kernel/include/kernel/ACPI/AML/Processor.h | 86 - kernel/include/kernel/ACPI/AML/Reference.h | 186 - kernel/include/kernel/ACPI/AML/Region.h | 116 - kernel/include/kernel/ACPI/AML/Register.h | 23 - kernel/include/kernel/ACPI/AML/Scope.h | 75 +- kernel/include/kernel/ACPI/AML/SizeOf.h | 60 - kernel/include/kernel/ACPI/AML/Sleep.h | 42 - kernel/include/kernel/ACPI/AML/Store.h | 53 - kernel/include/kernel/ACPI/AML/String.h | 69 - kernel/include/kernel/ACPI/AML/ThermalZone.h | 64 - kernel/include/kernel/ACPI/AML/Utils.h | 36 - kernel/include/kernel/ACPI/AML/While.h | 77 - kernel/include/kernel/ACPI/Headers.h | 5 +- kernel/kernel/ACPI/ACPI.cpp | 338 +- kernel/kernel/ACPI/AML.cpp | 60 - kernel/kernel/ACPI/AML/Field.cpp | 881 ----- kernel/kernel/ACPI/AML/Integer.cpp | 183 - kernel/kernel/ACPI/AML/NamedObject.cpp | 46 - kernel/kernel/ACPI/AML/Namespace.cpp | 673 ++-- kernel/kernel/ACPI/AML/Node.cpp | 3478 +++++++++++++++-- kernel/kernel/ACPI/AML/OpRegion.cpp | 806 ++++ kernel/kernel/ACPI/AML/Package.cpp | 57 - kernel/kernel/ACPI/AML/Register.cpp | 71 - kernel/kernel/ACPI/AML/Scope.cpp | 202 +- kernel/kernel/ACPI/AML/String.cpp | 75 - kernel/kernel/Process.cpp | 7 +- 55 files changed, 5230 insertions(+), 5913 deletions(-) delete mode 100644 kernel/include/kernel/ACPI/AML.h delete mode 100644 kernel/include/kernel/ACPI/AML/Alias.h delete mode 100644 kernel/include/kernel/ACPI/AML/Buffer.h delete mode 100644 kernel/include/kernel/ACPI/AML/Concat.h delete mode 100644 kernel/include/kernel/ACPI/AML/Conversion.h delete mode 100644 kernel/include/kernel/ACPI/AML/CopyObject.h delete mode 100644 kernel/include/kernel/ACPI/AML/Device.h delete mode 100644 kernel/include/kernel/ACPI/AML/Event.h delete mode 100644 kernel/include/kernel/ACPI/AML/Expression.h delete mode 100644 kernel/include/kernel/ACPI/AML/Field.h delete mode 100644 kernel/include/kernel/ACPI/AML/IfElse.h delete mode 100644 kernel/include/kernel/ACPI/AML/Index.h delete mode 100644 kernel/include/kernel/ACPI/AML/Integer.h delete mode 100644 kernel/include/kernel/ACPI/AML/Method.h delete mode 100644 kernel/include/kernel/ACPI/AML/Mutex.h delete mode 100644 kernel/include/kernel/ACPI/AML/NamedObject.h delete mode 100644 kernel/include/kernel/ACPI/AML/Names.h delete mode 100644 kernel/include/kernel/ACPI/AML/Notify.h delete mode 100644 kernel/include/kernel/ACPI/AML/ObjectType.h create mode 100644 kernel/include/kernel/ACPI/AML/OpRegion.h delete mode 100644 kernel/include/kernel/ACPI/AML/Package.h delete mode 100644 kernel/include/kernel/ACPI/AML/ParseContext.h delete mode 100644 kernel/include/kernel/ACPI/AML/Pkg.h delete mode 100644 kernel/include/kernel/ACPI/AML/PowerResource.h delete mode 100644 kernel/include/kernel/ACPI/AML/Processor.h delete mode 100644 kernel/include/kernel/ACPI/AML/Reference.h delete mode 100644 kernel/include/kernel/ACPI/AML/Region.h delete mode 100644 kernel/include/kernel/ACPI/AML/Register.h delete mode 100644 kernel/include/kernel/ACPI/AML/SizeOf.h delete mode 100644 kernel/include/kernel/ACPI/AML/Sleep.h delete mode 100644 kernel/include/kernel/ACPI/AML/Store.h delete mode 100644 kernel/include/kernel/ACPI/AML/String.h delete mode 100644 kernel/include/kernel/ACPI/AML/ThermalZone.h delete mode 100644 kernel/include/kernel/ACPI/AML/Utils.h delete mode 100644 kernel/include/kernel/ACPI/AML/While.h delete mode 100644 kernel/kernel/ACPI/AML.cpp delete mode 100644 kernel/kernel/ACPI/AML/Field.cpp delete mode 100644 kernel/kernel/ACPI/AML/Integer.cpp delete mode 100644 kernel/kernel/ACPI/AML/NamedObject.cpp create mode 100644 kernel/kernel/ACPI/AML/OpRegion.cpp delete mode 100644 kernel/kernel/ACPI/AML/Package.cpp delete mode 100644 kernel/kernel/ACPI/AML/Register.cpp delete mode 100644 kernel/kernel/ACPI/AML/String.cpp diff --git a/kernel/CMakeLists.txt b/kernel/CMakeLists.txt index 11dca457..ed7ef9a8 100644 --- a/kernel/CMakeLists.txt +++ b/kernel/CMakeLists.txt @@ -1,16 +1,10 @@ set(KERNEL_SOURCES font/prefs.psf.o kernel/ACPI/ACPI.cpp - kernel/ACPI/AML.cpp - kernel/ACPI/AML/Field.cpp - kernel/ACPI/AML/Integer.cpp - kernel/ACPI/AML/NamedObject.cpp kernel/ACPI/AML/Namespace.cpp kernel/ACPI/AML/Node.cpp - kernel/ACPI/AML/Package.cpp - kernel/ACPI/AML/Register.cpp + kernel/ACPI/AML/OpRegion.cpp kernel/ACPI/AML/Scope.cpp - kernel/ACPI/AML/String.cpp kernel/APIC.cpp kernel/BootInfo.cpp kernel/CPUID.cpp diff --git a/kernel/include/kernel/ACPI/ACPI.h b/kernel/include/kernel/ACPI/ACPI.h index 4706da17..04a13544 100644 --- a/kernel/include/kernel/ACPI/ACPI.h +++ b/kernel/include/kernel/ACPI/ACPI.h @@ -1,7 +1,6 @@ #pragma once #include -#include #include #include #include @@ -29,13 +28,8 @@ namespace Kernel::ACPI // 2: SAPIC BAN::ErrorOr enter_acpi_mode(uint8_t mode); - // This function will power off the system - // This function will return only if there was an error - void poweroff(); - - // This function will reset the system - // This function will return only if there was an error - void reset(); + BAN::ErrorOr poweroff(); + BAN::ErrorOr reset(); void handle_irq() override; @@ -45,9 +39,11 @@ namespace Kernel::ACPI FADT& fadt() { return *m_fadt; } - bool prepare_sleep(uint8_t sleep_state); + BAN::ErrorOr prepare_sleep(uint8_t sleep_state); void acpi_event_task(); + BAN::ErrorOr load_aml_tables(BAN::StringView name, bool all); + private: paddr_t m_header_table_paddr = 0; vaddr_t m_header_table_vaddr = 0; @@ -65,10 +61,12 @@ namespace Kernel::ACPI FADT* m_fadt { nullptr }; ThreadBlocker m_event_thread_blocker; - BAN::Array, 0xFF> m_gpe_methods; + + AML::Scope m_gpe_scope; + BAN::Array m_gpe_methods { nullptr }; bool m_hardware_reduced { false }; - BAN::RefPtr m_namespace; + AML::Namespace* m_namespace { nullptr }; }; } diff --git a/kernel/include/kernel/ACPI/AML.h b/kernel/include/kernel/ACPI/AML.h deleted file mode 100644 index 9c8be764..00000000 --- a/kernel/include/kernel/ACPI/AML.h +++ /dev/null @@ -1,11 +0,0 @@ -#pragma once - -#include -#include - -namespace Kernel::ACPI::AML -{ - - BAN::RefPtr initialize_namespace(); - -} diff --git a/kernel/include/kernel/ACPI/AML/Alias.h b/kernel/include/kernel/ACPI/AML/Alias.h deleted file mode 100644 index 499f5b9a..00000000 --- a/kernel/include/kernel/ACPI/AML/Alias.h +++ /dev/null @@ -1,48 +0,0 @@ -#pragma once - -#include -#include -#include - -namespace Kernel::ACPI::AML -{ - - struct Alias - { - static ParseResult parse(ParseContext& context) - { - ASSERT(context.aml_data.size() >= 1); - ASSERT(static_cast(context.aml_data[0]) == Byte::AliasOp); - context.aml_data = context.aml_data.slice(1); - - auto source_string = AML::NameString::parse(context.aml_data); - if (!source_string.has_value()) - return ParseResult::Failure; - - auto source_object = AML::Namespace::root_namespace()->find_object(context.scope, source_string.value(), AML::Namespace::FindMode::Normal); - auto alias_string = AML::NameString::parse(context.aml_data); - if (!alias_string.has_value()) - return ParseResult::Failure; - - if (!source_object) - { - AML_PRINT("Alias target could not be found"); - return ParseResult::Success; - } - - if (!Namespace::root_namespace()->add_named_object(context, alias_string.value(), source_object)) - return ParseResult::Success; - - #if AML_DEBUG_LEVEL >= 2 - AML_DEBUG_PRINT("Alias \""); - alias_string->debug_print(); - AML_DEBUG_PRINT("\" => "); - source_object->debug_print(0); - AML_DEBUG_PRINTLN(""); - #endif - - return ParseResult::Success; - } - }; - -} diff --git a/kernel/include/kernel/ACPI/AML/Buffer.h b/kernel/include/kernel/ACPI/AML/Buffer.h deleted file mode 100644 index 57a3ae39..00000000 --- a/kernel/include/kernel/ACPI/AML/Buffer.h +++ /dev/null @@ -1,312 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include - -namespace Kernel::ACPI::AML -{ - - struct Buffer final : public AML::Node - { - BAN::Vector buffer; - - Buffer() - : AML::Node(Node::Type::Buffer) - {} - - BAN::Optional logical_compare(BAN::RefPtr node, AML::Byte binaryop) - { - auto rhs_node = node ? node->convert(AML::Node::ConvBuffer) : BAN::RefPtr(); - if (!rhs_node) - { - AML_ERROR("Buffer logical compare RHS cannot be converted to buffer"); - return {}; - } - - (void)binaryop; - AML_TODO("Logical compare buffer"); - return {}; - } - - BAN::RefPtr convert(uint8_t mask) override - { - if (mask & AML::Node::ConvBuffer) - return this; - if (mask & AML::Node::ConvInteger) - return as_integer(); - if (mask & AML::Node::ConvString) - { - AML_TODO("Convert BufferField to String"); - return {}; - } - return {}; - } - - BAN::RefPtr store(BAN::RefPtr node) override - { - ASSERT(node); - auto conv_node = node->convert(AML::Node::ConvBuffer); - if (!conv_node) - { - AML_ERROR("Buffer store could not convert to buffer"); - return {}; - } - - auto& conv_buffer = static_cast(conv_node.ptr())->buffer; - MUST(buffer.resize(conv_buffer.size())); - for (size_t i = 0; i < buffer.size(); i++) - buffer[i] = conv_buffer[i]; - return this; - } - - static ParseResult parse(AML::ParseContext& context) - { - ASSERT(context.aml_data.size() >= 1); - ASSERT(static_cast(context.aml_data[0]) == Byte::BufferOp); - context.aml_data = context.aml_data.slice(1); - - auto buffer_pkg = AML::parse_pkg(context.aml_data); - if (!buffer_pkg.has_value()) - return ParseResult::Failure; - - auto buffer_context = context; - buffer_context.aml_data = buffer_pkg.value(); - - auto buffer_size_result = AML::parse_object(buffer_context); - if (!buffer_size_result.success()) - return ParseResult::Failure; - - auto buffer_size_node = buffer_size_result.node() ? buffer_size_result.node()->convert(AML::Node::ConvInteger) : BAN::RefPtr(); - if (!buffer_size_node) - { - AML_ERROR("Buffer size is not an integer"); - return ParseResult::Failure; - } - - const uint32_t actual_buffer_size = BAN::Math::max( - static_cast(buffer_size_node.ptr())->value, - buffer_context.aml_data.size() - ); - - auto buffer = MUST(BAN::RefPtr::create()); - MUST(buffer->buffer.resize(actual_buffer_size, 0)); - for (uint32_t i = 0; i < buffer_context.aml_data.size(); i++) - buffer->buffer[i] = buffer_context.aml_data[i]; - -#if AML_DEBUG_LEVEL >= 2 - buffer->debug_print(0); - AML_DEBUG_PRINTLN(""); -#endif - - return ParseResult(buffer); - } - - virtual void debug_print(int indent) const override - { - AML_DEBUG_PRINT_INDENT(indent); - AML_DEBUG_PRINT("Buffer ({} bytes)", buffer.size()); - } - - private: - BAN::RefPtr as_integer() - { - uint64_t value = 0; - for (size_t i = 0; i < BAN::Math::min(buffer.size(), 8); i++) - value |= static_cast(buffer[i]) << (8 * i); - return MUST(BAN::RefPtr::create(value)); - } - }; - - struct BufferField final : AML::NamedObject - { - BAN::RefPtr buffer; - size_t field_bit_offset; - size_t field_bit_size; - - template requires BAN::is_same_v || BAN::is_same_v - BufferField(AML::NameSeg name, BAN::RefPtr buffer, size_t field_bit_offset, size_t field_bit_size) - : AML::NamedObject(Node::Type::BufferField, name) - , buffer(buffer) - , field_bit_offset(field_bit_offset) - , field_bit_size(field_bit_size) - {} - - BAN::RefPtr convert(uint8_t mask) override - { - if (mask & AML::Node::ConvBufferField) - return this; - if (mask & AML::Node::ConvInteger) - return as_integer(); - if (mask & AML::Node::ConvBuffer) - { - AML_TODO("Convert BufferField to Buffer"); - return {}; - } - if (mask & AML::Node::ConvString) - { - AML_TODO("Convert BufferField to String"); - return {}; - } - return {}; - } - - BAN::RefPtr store(BAN::RefPtr node) override - { - ASSERT(buffer); - ASSERT(buffer->type == AML::Node::Type::Buffer || buffer->type == AML::Node::Type::String); - auto& buffer = (this->buffer->type == AML::Node::Type::Buffer) - ? static_cast(this->buffer.ptr())->buffer - : static_cast(this->buffer.ptr())->string; - ASSERT(field_bit_offset + field_bit_size <= buffer.size() * 8); - - auto value_node = node ? node->convert(AML::Node::ConvInteger) : BAN::RefPtr(); - if (!value_node) - return {}; - const auto value = static_cast(value_node.ptr())->value; - - // TODO: optimize for whole byte accesses - for (size_t i = 0; i < field_bit_size; i++) - { - const size_t bit = field_bit_offset + i; - buffer[bit / 8] &= ~(1 << (bit % 8)); - buffer[bit / 8] |= ((value >> i) & 1) << (bit % 8); - } - - return value_node; - } - - static ParseResult parse(AML::ParseContext& context) - { - ASSERT(context.aml_data.size() >= 1); - - bool offset_in_bytes; - size_t field_bit_size; - switch (static_cast(context.aml_data[0])) - { - case AML::Byte::CreateBitFieldOp: - field_bit_size = 1; - offset_in_bytes = false; - break; - case AML::Byte::CreateByteFieldOp: - field_bit_size = 8; - offset_in_bytes = true; - break; - case AML::Byte::CreateWordFieldOp: - field_bit_size = 16; - offset_in_bytes = true; - break; - case AML::Byte::CreateDWordFieldOp: - field_bit_size = 32; - offset_in_bytes = true; - break; - case AML::Byte::CreateQWordFieldOp: - field_bit_size = 64; - offset_in_bytes = true; - break; - case AML::Byte::ExtOpPrefix: - ASSERT(context.aml_data.size() >= 2); - ASSERT(static_cast(context.aml_data[1]) == AML::ExtOp::CreateFieldOp); - field_bit_size = 0; - offset_in_bytes = false; - break; - default: - ASSERT_NOT_REACHED(); - } - context.aml_data = context.aml_data.slice(1 + (static_cast(context.aml_data[0]) == AML::Byte::ExtOpPrefix)); - - auto buffer_result = AML::parse_object(context); - if (!buffer_result.success()) - return ParseResult::Failure; - auto buffer_node = buffer_result.node() ? buffer_result.node()->convert(AML::Node::ConvBuffer) : BAN::RefPtr(); - if (!buffer_node || buffer_node->type != Node::Type::Buffer) - { - AML_ERROR("Buffer source does not evaluate to a Buffer"); - return ParseResult::Failure; - } - auto buffer = BAN::RefPtr(static_cast(buffer_node.ptr())); - - auto index_result = AML::parse_object(context); - if (!index_result.success()) - return ParseResult::Failure; - auto index_node = index_result.node() ? index_result.node()->convert(AML::Node::ConvInteger) : BAN::RefPtr(); - if (!index_node) - { - AML_ERROR("Failed to parse index for BufferField"); - return ParseResult::Failure; - } - - if (field_bit_size == 0) - { - auto bit_count_result = AML::parse_object(context); - if (!bit_count_result.success()) - return ParseResult::Failure; - auto bit_count_node = bit_count_result.node() ? bit_count_result.node()->convert(AML::Node::ConvInteger) : BAN::RefPtr(); - if (!bit_count_node) - { - AML_ERROR("Failed to parse bit count for BufferField"); - return ParseResult::Failure; - } - field_bit_size = static_cast(bit_count_node.ptr())->value; - } - - auto field_name = AML::NameString::parse(context.aml_data); - if (!field_name.has_value()) - return ParseResult::Failure; - if (field_name->path.empty()) - { - AML_ERROR("Empty field name for BufferField"); - return ParseResult::Failure; - } - - size_t field_bit_offset = static_cast(index_node.ptr())->value; - if (offset_in_bytes) - field_bit_offset *= 8; - - auto field = MUST(BAN::RefPtr::create(field_name->path.back(), buffer, field_bit_offset, field_bit_size)); - if (!Namespace::root_namespace()->add_named_object(context, field_name.value(), field)) - return ParseResult::Success; - -#if AML_DEBUG_LEVEL >= 2 - field->debug_print(0); - AML_DEBUG_PRINTLN(""); -#endif - - return ParseResult::Success; - } - - virtual void debug_print(int indent) const override - { - AML_DEBUG_PRINT_INDENT(indent); - AML_DEBUG_PRINT("BufferField {} at bit offset {} ({} bits) to { ", name, field_bit_offset, field_bit_size); - buffer->debug_print(0); - AML_DEBUG_PRINT(" }"); - } - - private: - BAN::RefPtr as_integer() - { - ASSERT(buffer); - ASSERT(buffer->type == AML::Node::Type::Buffer || buffer->type == AML::Node::Type::String); - - const auto& buffer = (this->buffer->type == AML::Node::Type::Buffer) - ? static_cast(this->buffer.ptr())->buffer - : static_cast(this->buffer.ptr())->string; - - uint64_t value = 0; - - // TODO: optimize for whole byte accesses - for (size_t i = 0; i < BAN::Math::min(field_bit_size, 64); i++) - { - const size_t bit = field_bit_offset + i; - value |= static_cast((buffer[bit / 8] >> (bit % 8)) & 1) << i; - } - - return MUST(BAN::RefPtr::create(value)); - } - }; - -} diff --git a/kernel/include/kernel/ACPI/AML/Bytes.h b/kernel/include/kernel/ACPI/AML/Bytes.h index 22252073..2737ca09 100644 --- a/kernel/include/kernel/ACPI/AML/Bytes.h +++ b/kernel/include/kernel/ACPI/AML/Bytes.h @@ -145,19 +145,35 @@ namespace Kernel::ACPI::AML DataRegionOp = 0x88, }; - static constexpr bool is_digit_char(uint8_t ch) + inline constexpr bool is_digit_char(uint8_t ch) { return '0' <= ch && ch <= '9'; } - static constexpr bool is_lead_name_char(uint8_t ch) + inline constexpr bool is_lead_name_char(uint8_t ch) { return ('A' <= ch && ch <= 'Z') || ch == '_'; } - static constexpr bool is_name_char(uint8_t ch) + inline constexpr bool is_name_char(uint8_t ch) { return is_lead_name_char(ch) || is_digit_char(ch); } + inline constexpr bool is_name_string_start(uint8_t ch) + { + if (is_lead_name_char(ch)) + return true; + switch (static_cast(ch)) + { + case AML::Byte::RootChar: + case AML::Byte::ParentPrefixChar: + case AML::Byte::MultiNamePrefix: + case AML::Byte::DualNamePrefix: + return true; + default: + return false; + } + } + } diff --git a/kernel/include/kernel/ACPI/AML/Concat.h b/kernel/include/kernel/ACPI/AML/Concat.h deleted file mode 100644 index 6e70a167..00000000 --- a/kernel/include/kernel/ACPI/AML/Concat.h +++ /dev/null @@ -1,124 +0,0 @@ -#pragma once - -#include -#include -#include - -namespace Kernel::ACPI::AML -{ - - struct Concat - { - static ParseResult parse(ParseContext& context) - { - ASSERT(context.aml_data.size() >= 1); - ASSERT(static_cast(context.aml_data[0]) == Byte::ConcatOp); - context.aml_data = context.aml_data.slice(1); - - auto source1_result = AML::parse_object(context); - if (!source1_result.success()) - return ParseResult::Failure; - auto source1 = source1_result.node() ? source1_result.node()->to_underlying() : BAN::RefPtr(); - - auto source2_result = AML::parse_object(context); - if (!source2_result.success()) - return ParseResult::Failure; - auto source2 = source1_result.node() ? source1_result.node()->to_underlying() : BAN::RefPtr(); - - if (!source1 || !source2) - { - AML_ERROR("ConcatOp sources could not be parsed"); - return ParseResult::Failure; - } - - switch (source1->type) - { - case AML::Node::Type::Integer: - source1 = source1->convert(AML::Node::ConvBuffer); - source2 = source2->convert(AML::Node::ConvBuffer); - break; - case AML::Node::Type::String: - source2 = source2->convert(AML::Node::ConvString); - break; - case AML::Node::Type::Buffer: - source2 = source2->convert(AML::Node::ConvBuffer); - break; - default: - source1 = source1->convert(AML::Node::ConvString); - source2 = source2->convert(AML::Node::ConvString); - break; - } - - if (!source1 || !source2) - { - AML_ERROR("ConcatOp sources could not be converted"); - return ParseResult::Failure; - } - - ASSERT(source1->type == source2->type); - - BAN::RefPtr result; - BAN::Vector* result_data = nullptr; - BAN::Vector* source1_data = nullptr; - BAN::Vector* source2_data = nullptr; - - switch (source1->type) - { - case AML::Node::Type::String: - result = MUST(BAN::RefPtr::create()); - result_data = &static_cast(result.ptr())->string; - source1_data = &static_cast(source1.ptr())->string; - source2_data = &static_cast(source2.ptr())->string; - break; - case AML::Node::Type::Buffer: - result = MUST(BAN::RefPtr::create()); - result_data = &static_cast(result.ptr())->buffer; - source1_data = &static_cast(source1.ptr())->buffer; - source2_data = &static_cast(source2.ptr())->buffer; - break; - default: - ASSERT_NOT_REACHED(); - } - - ASSERT(result_data && source1_data && source2_data); - - MUST(result_data->resize(source1_data->size() + source2_data->size())); - for (size_t i = 0; i < source1_data->size(); i++) - (*result_data)[i] = (*source1_data)[i]; - for (size_t i = 0; i < source2_data->size(); i++) - (*result_data)[source1_data->size() + i] = (*source2_data)[i]; - -#if AML_DEBUG_LEVEL >= 2 - AML_DEBUG_PRINT("Concat "); - source1->debug_print(0); - AML_DEBUG_PRINT(", "); - source2->debug_print(0); - AML_DEBUG_PRINTLN(""); -#endif - - if (context.aml_data.size() < 1) - return ParseResult::Failure; - - if (context.aml_data[0] == 0x00) - context.aml_data = context.aml_data.slice(1); - else - { - auto destination_result = AML::parse_object(context); - if (!destination_result.success()) - return ParseResult::Failure; - auto destination = destination_result.node(); - if (!destination) - { - AML_ERROR("IndexOp failed to resolve destination"); - return ParseResult::Failure; - } - - if (!destination->store(result)) - return ParseResult::Failure; - } - - return ParseResult(result); - } - }; - -} diff --git a/kernel/include/kernel/ACPI/AML/Conversion.h b/kernel/include/kernel/ACPI/AML/Conversion.h deleted file mode 100644 index d896ac5b..00000000 --- a/kernel/include/kernel/ACPI/AML/Conversion.h +++ /dev/null @@ -1,124 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -namespace Kernel::ACPI::AML -{ - - struct Conversion - { - static ParseResult parse(AML::ParseContext& context) - { - const auto opcode = static_cast(context.aml_data[0]); - context.aml_data = context.aml_data.slice(1); - - switch (opcode) - { - case AML::Byte::ToBufferOp: - case AML::Byte::ToHexStringOp: - case AML::Byte::ToIntegerOp: - case AML::Byte::ToStringOp: - break; - default: - ASSERT_NOT_REACHED(); - } - - auto data_result = AML::parse_object(context); - if (!data_result.success()) - return ParseResult::Failure; - auto data_node = data_result.node() ? data_result.node()->to_underlying() : BAN::RefPtr(); - if (!data_node) - { - AML_ERROR("Conversion {2H} data could not be evaluated", static_cast(opcode)); - return ParseResult::Failure; - } - - if (context.aml_data.size() < 1) - { - AML_ERROR("Conversion {2H} missing target", static_cast(opcode)); - return ParseResult::Failure; - } - - BAN::RefPtr target_node; - if (context.aml_data[0] == 0x00) - context.aml_data = context.aml_data.slice(1); - else - { - auto target_result = AML::parse_object(context); - if (!target_result.success()) - return ParseResult::Failure; - target_node = target_result.node(); - if (!target_node) - { - AML_ERROR("Conversion {2H} target invalid", static_cast(opcode)); - return ParseResult::Failure; - } - } - - BAN::RefPtr converted; - switch (opcode) - { - case AML::Byte::ToBufferOp: - converted = data_node->convert(AML::Node::ConvBuffer); - break; - case AML::Byte::ToIntegerOp: - converted = data_node->convert(AML::Node::ConvInteger); - break; - case AML::Byte::ToStringOp: - converted = data_node->convert(AML::Node::ConvString); - break; - case AML::Byte::ToHexStringOp: - { - switch (data_node->type) - { - case AML::Node::Type::Integer: - converted = MUST(BAN::RefPtr::create( - MUST(BAN::String::formatted("0x{H}", static_cast(data_node.ptr())->value)) - )); - break; - case AML::Node::Type::String: - converted = data_node->copy(); - break; - case AML::Node::Type::Buffer: - { - const auto& buffer = static_cast(data_node.ptr())->buffer; - - BAN::String temp; - for (size_t i = 0; i < buffer.size(); i++) - { - const char* format = (i == 0) ? "0x{H}" : ", 0x{H}"; - MUST(temp.append(MUST(BAN::String::formatted(format, buffer[i])))); - } - - converted = MUST(BAN::RefPtr::create(temp)); - break; - } - default: - break; - } - break; - } - default: - ASSERT_NOT_REACHED(); - } - - if (!converted) - { - AML_ERROR("Conversion {2H} could not convert from node type {}", static_cast(opcode), static_cast(data_node->type)); - return ParseResult::Failure; - } - - if (target_node && !target_node->store(converted)) - { - AML_ERROR("Conversion {2H} failed to store converted value", static_cast(opcode)); - return ParseResult::Failure; - } - - return ParseResult(converted); - } - }; - -} diff --git a/kernel/include/kernel/ACPI/AML/CopyObject.h b/kernel/include/kernel/ACPI/AML/CopyObject.h deleted file mode 100644 index f5fe8c1b..00000000 --- a/kernel/include/kernel/ACPI/AML/CopyObject.h +++ /dev/null @@ -1,65 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -namespace Kernel::ACPI::AML -{ - - struct CopyObject - { - static ParseResult parse(ParseContext& context) - { - ASSERT(context.aml_data.size() >= 1); - ASSERT(static_cast(context.aml_data[0]) == Byte::CopyObjectOp); - context.aml_data = context.aml_data.slice(1); - - auto source_result = AML::parse_object(context); - if (!source_result.success()) - return ParseResult::Failure; - auto source = source_result.node() - ? source_result.node()->to_underlying() - : BAN::RefPtr(); - if (!source) - { - AML_ERROR("CopyObject source is null"); - return ParseResult::Failure; - } - - auto destination_result = AML::parse_object(context); - if (!destination_result.success()) - return ParseResult::Failure; - auto destination = destination_result.node(); - if (!destination) - { - AML_ERROR("CopyObject destination is null"); - return ParseResult::Failure; - } - -#if AML_DEBUG_LEVEL >= 2 - AML_DEBUG_PRINTLN("CopyObject {"); - source->debug_print(1); - AML_DEBUG_PRINTLN(""); - AML_DEBUG_PRINTLN("} to {"); - destination->debug_print(1); - AML_DEBUG_PRINTLN(""); - AML_DEBUG_PRINTLN("}"); -#endif - - switch (destination->type) - { - case AML::Node::Type::Name: - static_cast(destination.ptr())->object = source->copy(); - return source; - case AML::Node::Type::Register: - static_cast(destination.ptr())->value = source->copy(); - return source; - default: - ASSERT_NOT_REACHED(); - } - } - }; - -} diff --git a/kernel/include/kernel/ACPI/AML/Device.h b/kernel/include/kernel/ACPI/AML/Device.h deleted file mode 100644 index cb6fd674..00000000 --- a/kernel/include/kernel/ACPI/AML/Device.h +++ /dev/null @@ -1,59 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -namespace Kernel::ACPI::AML -{ - - struct Device final : public AML::Scope - { - Device(NameSeg name) - : Scope(Node::Type::Device, name) - {} - - BAN::RefPtr convert(uint8_t) override { return {}; } - - static ParseResult parse(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::DeviceOp); - context.aml_data = context.aml_data.slice(2); - - auto device_pkg = AML::parse_pkg(context.aml_data); - if (!device_pkg.has_value()) - return ParseResult::Failure; - - auto name_string = AML::NameString::parse(device_pkg.value()); - if (!name_string.has_value()) - return ParseResult::Failure; - - auto device = MUST(BAN::RefPtr::create(name_string->path.back())); - if (!Namespace::root_namespace()->add_named_object(context, name_string.value(), device)) - return ParseResult::Success; - - return device->enter_context_and_parse_term_list(context, name_string.value(), device_pkg.value()); - } - - virtual void debug_print(int indent) const override - { - AML_DEBUG_PRINT_INDENT(indent); - AML_DEBUG_PRINT("Device "); - name.debug_print(); - AML_DEBUG_PRINTLN(" {"); - Namespace::root_namespace()->for_each_child(scope, - [&](const auto&, const auto& child) - { - child->debug_print(indent + 1); - AML_DEBUG_PRINTLN(""); - } - ); - AML_DEBUG_PRINT_INDENT(indent); - AML_DEBUG_PRINT("}"); - } - }; - -} diff --git a/kernel/include/kernel/ACPI/AML/Event.h b/kernel/include/kernel/ACPI/AML/Event.h deleted file mode 100644 index 1a58171c..00000000 --- a/kernel/include/kernel/ACPI/AML/Event.h +++ /dev/null @@ -1,148 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include - -namespace Kernel::ACPI::AML -{ - - struct Event final : public AML::NamedObject - { - BAN::Atomic signal_count { 0 }; - ThreadBlocker thread_blocker; - - Event(NameSeg name) - : NamedObject(Node::Type::Event, name) - {} - - BAN::RefPtr convert(uint8_t) override { return {}; } - - 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(); - 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_node = timeout_result.node() - ? timeout_result.node()->convert(AML::Node::ConvInteger) - : BAN::RefPtr(); - if (!timeout_node) - { - AML_ERROR("Wait timeout does not evaluate to integer"); - return ParseResult::Failure; - } - const auto timeout_value = static_cast(timeout_node.ptr())->value; - - 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/Expression.h b/kernel/include/kernel/ACPI/AML/Expression.h deleted file mode 100644 index bc5af507..00000000 --- a/kernel/include/kernel/ACPI/AML/Expression.h +++ /dev/null @@ -1,283 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include - -namespace Kernel::ACPI::AML -{ - - struct Expression - { - static ParseResult parse(ParseContext& context) - { - ASSERT(context.aml_data.size() >= 1); - switch (static_cast(context.aml_data[0])) - { - // unary - case AML::Byte::IncrementOp: - case AML::Byte::DecrementOp: - { - auto opcode = (static_cast(context.aml_data[0]) == AML::Byte::IncrementOp) ? AML::Byte::AddOp : AML::Byte::SubtractOp; - context.aml_data = context.aml_data.slice(1); - - auto source_result = AML::parse_object(context); - if (!source_result.success()) - return ParseResult::Failure; - auto conv_node = source_result.node() ? source_result.node()->convert(AML::Node::ConvInteger) : BAN::RefPtr(); - if (!conv_node) - { - AML_ERROR("UnaryOp source not integer, type {}", static_cast(source_result.node()->type)); - return ParseResult::Failure; - } - - auto source_node = static_cast(conv_node.ptr()); - if (source_node->constant) - { - AML_ERROR("UnaryOp source is constant"); - return ParseResult::Failure; - } - - source_node->value += (opcode == AML::Byte::AddOp) ? 1 : -1; - return ParseResult(source_node); - } - case AML::Byte::NotOp: - { - auto source_result = AML::parse_object(context); - if (!source_result.success()) - return ParseResult::Failure; - auto source_conv = source_result.node() ? source_result.node()->convert(AML::Node::ConvInteger) : BAN::RefPtr(); - if (!source_conv) - { - AML_ERROR("NotOp source not an integer, type {}", - static_cast(source_result.node()->type) - ); - if (source_result.node()) - source_result.node()->debug_print(1); - AML_DEBUG_PRINTLN(""); - return ParseResult::Failure; - } - const auto source_value = static_cast(source_conv.ptr())->value; - - BAN::RefPtr target_node; - if (context.aml_data[0] == 0x00) - context.aml_data = context.aml_data.slice(1); - else - { - auto target_result = AML::parse_object(context); - if (!target_result.success()) - return ParseResult::Failure; - target_node = target_result.node(); - if (!target_node) - { - AML_ERROR("NotOp target invalid"); - return ParseResult::Failure; - } - } - - auto result_node = MUST(BAN::RefPtr::create(~source_value)); - if (target_node && !target_node->store(result_node)) - { - AML_ERROR("NotOp failed to store result"); - return ParseResult::Failure; - } - - return ParseResult(result_node); - } - case AML::Byte::LNotOp: - { - context.aml_data = context.aml_data.slice(1); - - auto source_result = AML::parse_object(context); - if (!source_result.success()) - return ParseResult::Failure; - auto conv_node = source_result.node() ? source_result.node()->convert(AML::Node::ConvInteger) : BAN::RefPtr(); - if (!conv_node) - { - AML_ERROR("UnaryOp source not integer, type {}", static_cast(source_result.node()->type)); - return ParseResult::Failure; - } - auto source_node = static_cast(conv_node.ptr()); - if (!source_node) - { - AML_ERROR("Logical NotOp source is not integer"); - return ParseResult::Failure; - } - - auto result = source_node->value ? Integer::Constants::Zero : Integer::Constants::Ones; - return ParseResult(result); - } - case AML::Byte::AddOp: - case AML::Byte::AndOp: - case AML::Byte::ModOp: - case AML::Byte::MultiplyOp: - case AML::Byte::NandOp: - case AML::Byte::NorOp: - case AML::Byte::OrOp: - case AML::Byte::ShiftLeftOp: - case AML::Byte::ShiftRightOp: - case AML::Byte::SubtractOp: - case AML::Byte::XorOp: - return parse_binary_op(context); - case AML::Byte::LAndOp: - case AML::Byte::LEqualOp: - case AML::Byte::LGreaterOp: - case AML::Byte::LLessOp: - case AML::Byte::LOrOp: - return parse_logical_binary_op(context); - case AML::Byte::DivideOp: - AML_TODO("DivideOp"); - return ParseResult::Failure; - default: - ASSERT_NOT_REACHED(); - } - } - - private: - static ParseResult parse_binary_op(ParseContext& context) - { - auto opcode = static_cast(context.aml_data[0]); - context.aml_data = context.aml_data.slice(1); - - auto lhs_result = AML::parse_object(context); - if (!lhs_result.success()) - return ParseResult::Failure; - auto lhs_conv = lhs_result.node() ? lhs_result.node()->convert(AML::Node::ConvInteger) : BAN::RefPtr(); - if (!lhs_conv) - { - AML_ERROR("BinaryOP {2H} LHS not an integer, type {}", - static_cast(opcode), - static_cast(lhs_result.node()->type) - ); - if (lhs_result.node()) - lhs_result.node()->debug_print(1); - AML_DEBUG_PRINTLN(""); - return ParseResult::Failure; - } - const auto lhs_value = static_cast(lhs_conv.ptr())->value; - - auto rhs_result = AML::parse_object(context); - if (!rhs_result.success()) - return ParseResult::Failure; - auto rhs_conv = rhs_result.node() ? rhs_result.node()->convert(AML::Node::ConvInteger) : BAN::RefPtr(); - if (!rhs_conv) - { - AML_ERROR("BinaryOP {2H} RHS not an integer", static_cast(opcode)); - if (rhs_result.node()) - rhs_result.node()->debug_print(1); - AML_DEBUG_PRINTLN(""); - return ParseResult::Failure; - } - const auto rhs_value = static_cast(rhs_conv.ptr())->value; - - if (context.aml_data.size() < 1) - { - AML_ERROR("BinaryOP {2H} missing target", static_cast(opcode)); - return ParseResult::Failure; - } - - BAN::RefPtr target_node; - if (context.aml_data[0] == 0x00) - context.aml_data = context.aml_data.slice(1); - else - { - auto target_result = AML::parse_object(context); - if (!target_result.success()) - return ParseResult::Failure; - target_node = target_result.node(); - if (!target_node) - { - AML_ERROR("BinaryOP {2H} target invalid", static_cast(opcode)); - return ParseResult::Failure; - } - } - - uint64_t (*func)(uint64_t, uint64_t) = nullptr; - switch (opcode) - { - case AML::Byte::AddOp: func = [](uint64_t a, uint64_t b) { return a + b; }; break; - case AML::Byte::AndOp: func = [](uint64_t a, uint64_t b) { return a & b; }; break; - case AML::Byte::ModOp: func = [](uint64_t a, uint64_t b) { return a % b; }; break; - case AML::Byte::MultiplyOp: func = [](uint64_t a, uint64_t b) { return a * b; }; break; - case AML::Byte::NandOp: func = [](uint64_t a, uint64_t b) { return ~(a & b); }; break; - case AML::Byte::NorOp: func = [](uint64_t a, uint64_t b) { return ~(a | b); }; break; - case AML::Byte::OrOp: func = [](uint64_t a, uint64_t b) { return a | b; }; break; - case AML::Byte::ShiftLeftOp: func = [](uint64_t a, uint64_t b) { return a << b; }; break; - case AML::Byte::ShiftRightOp: func = [](uint64_t a, uint64_t b) { return a >> b; }; break; - case AML::Byte::SubtractOp: func = [](uint64_t a, uint64_t b) { return a - b; }; break; - case AML::Byte::XorOp: func = [](uint64_t a, uint64_t b) { return a ^ b; }; break; - default: - ASSERT_NOT_REACHED(); - } - - auto result_node = MUST(BAN::RefPtr::create(func(lhs_value, rhs_value))); - if (target_node && !target_node->store(result_node)) - { - AML_ERROR("BinaryOp {2H} failed to store result", static_cast(opcode)); - return ParseResult::Failure; - } - - return ParseResult(result_node); - } - - static ParseResult parse_logical_binary_op(ParseContext& context) - { - auto opcode = static_cast(context.aml_data[0]); - context.aml_data = context.aml_data.slice(1); - - uint8_t mask; - switch (opcode) - { - case AML::Byte::LAndOp: - case AML::Byte::LOrOp: - mask = AML::Node::ConvInteger; - break; - case AML::Byte::LEqualOp: - case AML::Byte::LGreaterOp: - case AML::Byte::LLessOp: - mask = AML::Node::ConvInteger | AML::Node::ConvString | AML::Node::ConvBuffer; - break; - default: - ASSERT_NOT_REACHED(); - } - - auto lhs_result = AML::parse_object(context); - if (!lhs_result.success()) - return ParseResult::Failure; - auto lhs_node = lhs_result.node() ? lhs_result.node()->convert(mask) : BAN::RefPtr(); - if (!lhs_node) - { - AML_TODO("Logical BinaryOP {2H} LHS evaluated to nothing", static_cast(opcode)); - return ParseResult::Failure; - } - - auto rhs_result = AML::parse_object(context); - if (!rhs_result.success()) - return ParseResult::Failure; - - BAN::Optional result = false; - switch (lhs_node->type) - { - case AML::Node::Type::Integer: - result = static_cast(lhs_node.ptr())->logical_compare(rhs_result.node(), opcode); - break; - case AML::Node::Type::Buffer: - result = static_cast(lhs_node.ptr())->logical_compare(rhs_result.node(), opcode); - break; - case AML::Node::Type::String: - result = static_cast(lhs_node.ptr())->logical_compare(rhs_result.node(), opcode); - break; - default: - ASSERT_NOT_REACHED(); - } - - if (!result.has_value()) - return ParseResult::Failure; - - return ParseResult(result.value() ? AML::Integer::Constants::Ones : AML::Integer::Constants::Zero); - } - }; - -} diff --git a/kernel/include/kernel/ACPI/AML/Field.h b/kernel/include/kernel/ACPI/AML/Field.h deleted file mode 100644 index 04d577f1..00000000 --- a/kernel/include/kernel/ACPI/AML/Field.h +++ /dev/null @@ -1,199 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -namespace Kernel::ACPI::AML -{ - - struct FieldRules - { - enum class AccessType - { - Any = 0, - Byte = 1, - Word = 2, - DWord = 3, - QWord = 4, - Buffer = 5, - }; - AccessType access_type; - - enum class LockRule - { - NoLock = 0, - Lock = 1, - }; - LockRule lock_rule; - - enum class UpdateRule - { - Preserve = 0, - WriteAsOnes = 1, - WriteAsZeros = 2, - }; - UpdateRule update_rule; - - enum class AccessAttrib - { - Normal = 0, - Bytes = 1, - RawBytes = 2, - RawProcessBytes = 3, - }; - AccessAttrib access_attrib = AccessAttrib::Normal; - uint8_t access_length = 0; - }; - - struct FieldElement final : public AML::NamedObject - { - uint64_t bit_offset; - uint64_t bit_count; - - FieldRules access_rules; - - BAN::RefPtr op_region; - - FieldElement(NameSeg name, uint64_t bit_offset, uint64_t bit_count, FieldRules access_rules) - : NamedObject(Node::Type::FieldElement, name) - , bit_offset(bit_offset) - , bit_count(bit_count) - , access_rules(access_rules) - {} - - BAN::RefPtr convert(uint8_t mask) override - { - if (mask & AML::Node::ConvInteger) - return as_integer(); - if (mask & AML::Node::ConvBuffer) - { - AML_TODO("Convert BankFieldElement to Buffer"); - return {}; - } - if (mask & AML::Node::ConvString) - { - AML_TODO("Convert BankFieldElement to String"); - return {}; - } - return {}; - } - - BAN::RefPtr store(BAN::RefPtr source) override; - - void debug_print(int indent) const override; - - private: - BAN::RefPtr as_integer(); - - BAN::Optional evaluate_internal(); - bool store_internal(uint64_t value); - - friend struct IndexFieldElement; - friend struct BankFieldElement; - }; - - struct Field - { - static ParseResult parse(ParseContext& context); - }; - - struct IndexFieldElement final : public AML::NamedObject - { - uint64_t bit_offset; - uint64_t bit_count; - - FieldRules access_rules; - - BAN::RefPtr index_element; - BAN::RefPtr data_element; - - IndexFieldElement(NameSeg name, uint64_t bit_offset, uint64_t bit_count, FieldRules access_rules) - : NamedObject(Node::Type::IndexFieldElement, name) - , bit_offset(bit_offset) - , bit_count(bit_count) - , access_rules(access_rules) - {} - - BAN::RefPtr convert(uint8_t mask) override - { - if (mask & AML::Node::ConvInteger) - if (auto node = as_integer()) - return node; - if (mask & AML::Node::ConvBuffer) - { - AML_TODO("convert BankFieldElement to Buffer"); - return {}; - } - if (mask & AML::Node::ConvString) - { - AML_TODO("convert BankFieldElement to String"); - return {}; - } - return {}; - } - - BAN::RefPtr store(BAN::RefPtr source) override; - - void debug_print(int indent) const override; - - private: - BAN::RefPtr as_integer(); - }; - - struct IndexField - { - static ParseResult parse(ParseContext& context); - }; - - struct BankFieldElement final : public AML::NamedObject - { - uint64_t bit_offset; - uint64_t bit_count; - - FieldRules access_rules; - - BAN::RefPtr op_region; - BAN::RefPtr bank_selector; - uint64_t bank_value; - - BankFieldElement(NameSeg name, uint64_t bit_offset, uint64_t bit_count, FieldRules access_rules) - : NamedObject(Node::Type::BankFieldElement, name) - , bit_offset(bit_offset) - , bit_count(bit_count) - , access_rules(access_rules) - {} - - BAN::RefPtr convert(uint8_t mask) override - { - if (mask & AML::Node::ConvInteger) - if (auto node = as_integer()) - return node; - if (mask & AML::Node::ConvBuffer) - { - AML_TODO("convert BankFieldElement to Buffer"); - return {}; - } - if (mask & AML::Node::ConvString) - { - AML_TODO("convert BankFieldElement to String"); - return {}; - } - return {}; - } - - BAN::RefPtr store(BAN::RefPtr source) override; - - void debug_print(int indent) const override; - - private: - BAN::RefPtr as_integer(); - }; - - struct BankField - { - static ParseResult parse(ParseContext& context); - }; - -} diff --git a/kernel/include/kernel/ACPI/AML/IfElse.h b/kernel/include/kernel/ACPI/AML/IfElse.h deleted file mode 100644 index 3d5322b6..00000000 --- a/kernel/include/kernel/ACPI/AML/IfElse.h +++ /dev/null @@ -1,65 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -namespace Kernel::ACPI::AML -{ - - struct IfElse - { - static ParseResult parse(ParseContext& context) - { - ASSERT(context.aml_data.size() >= 1); - ASSERT(static_cast(context.aml_data[0]) == Byte::IfOp); - context.aml_data = context.aml_data.slice(1); - - auto if_pkg = AML::parse_pkg(context.aml_data); - if (!if_pkg.has_value()) - return ParseResult::Failure; - - auto outer_aml_data = context.aml_data; - context.aml_data = if_pkg.value(); - - auto predicate_result = AML::parse_object(context); - if (!predicate_result.success()) - return ParseResult::Failure; - auto predicate_node = predicate_result.node() ? predicate_result.node()->convert(AML::Node::ConvInteger) : BAN::RefPtr(); - if (!predicate_node) - { - AML_ERROR("If predicate is not an integer"); - return ParseResult::Failure; - } - const auto predicate_value = static_cast(predicate_node.ptr())->value; - - // Else - BAN::ConstByteSpan else_pkg; - if (outer_aml_data.size() >= 1 && static_cast(outer_aml_data[0]) == Byte::ElseOp) - { - outer_aml_data = outer_aml_data.slice(1); - auto else_pkg_result = AML::parse_pkg(outer_aml_data); - if (!else_pkg_result.has_value()) - return ParseResult::Failure; - else_pkg = else_pkg_result.value(); - } - if (predicate_value == 0) - context.aml_data = else_pkg; - - while (context.aml_data.size() > 0) - { - auto object_result = AML::parse_object(context); - if (object_result.returned() || object_result.breaked() || object_result.continued()) - return object_result; - if (!object_result.success()) - return ParseResult::Failure; - } - - context.aml_data = outer_aml_data; - - return ParseResult::Success; - } - }; - -} diff --git a/kernel/include/kernel/ACPI/AML/Index.h b/kernel/include/kernel/ACPI/AML/Index.h deleted file mode 100644 index 91977547..00000000 --- a/kernel/include/kernel/ACPI/AML/Index.h +++ /dev/null @@ -1,126 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include - -namespace Kernel::ACPI::AML -{ - - struct Index - { - static ParseResult parse(ParseContext& context) - { - ASSERT(context.aml_data.size() >= 1); - ASSERT(static_cast(context.aml_data[0]) == Byte::IndexOp); - context.aml_data = context.aml_data.slice(1); - - auto source_result = AML::parse_object(context); - if (!source_result.success()) - return ParseResult::Failure; - auto source = source_result.node() ? source_result.node()->to_underlying() : BAN::RefPtr(); - if (source && source->type != AML::Node::Type::Package) - source = source->convert(AML::Node::ConvBuffer | AML::Node::ConvInteger | AML::Node::ConvString); - if (!source) - { - AML_ERROR("IndexOp source could not be converted"); - return ParseResult::Failure; - } - - auto index_result = AML::parse_object(context); - if (!index_result.success()) - return ParseResult::Failure; - auto index_node = index_result.node() - ? index_result.node()->convert(AML::Node::ConvInteger) - : BAN::RefPtr(); - if (!index_node) - { - AML_ERROR("IndexOp index is not an integer"); - return ParseResult::Failure; - } - const auto index = static_cast(index_node.ptr())->value; - - BAN::RefPtr result; - switch (source->type) - { - case AML::Node::Type::Buffer: - { - auto buffer = BAN::RefPtr(static_cast(source.ptr())); - if (index >= buffer->buffer.size()) - { - AML_ERROR("IndexOp index is out of buffer bounds"); - return ParseResult::Failure; - } - auto buffer_field = MUST(BAN::RefPtr::create(NameSeg(""_sv), buffer, index * 8, 8)); - result = MUST(BAN::RefPtr::create(buffer_field)); - break; - } - case AML::Node::Type::Package: - { - auto package = static_cast(source.ptr()); - if (index >= package->elements.size()) - { - AML_ERROR("IndexOp index is out of package bounds"); - return ParseResult::Failure; - } - auto package_element = package->elements[index]; - if (!package_element) - { - AML_ERROR("IndexOp target is null package element"); - return ParseResult::Failure; - } - result = MUST(BAN::RefPtr::create(package_element)); - break; - } - case AML::Node::Type::String: - { - auto string = BAN::RefPtr(static_cast(source.ptr())); - if (index >= string->string.size()) - { - AML_ERROR("IndexOp index is out of string bounds"); - return ParseResult::Failure; - } - auto buffer_field = MUST(BAN::RefPtr::create(NameSeg(""_sv), string, index * 8, 8)); - result = MUST(BAN::RefPtr::create(buffer_field)); - break; - } - default: - AML_ERROR("IndexOp source is not a Buffer, Package, or String"); - return ParseResult::Failure; - } - -#if AML_DEBUG_LEVEL >= 2 - AML_DEBUG_PRINT("Index {}, ", index); - source->debug_print(0); - AML_DEBUG_PRINTLN(""); -#endif - - if (context.aml_data.size() < 1) - return ParseResult::Failure; - - if (context.aml_data[0] == 0x00) - context.aml_data = context.aml_data.slice(1); - else - { - auto destination_result = AML::parse_object(context); - if (!destination_result.success()) - return ParseResult::Failure; - auto destination = destination_result.node(); - if (!destination) - { - AML_ERROR("IndexOp failed to resolve destination"); - return ParseResult::Failure; - } - - if (!destination->store(result)) - return ParseResult::Failure; - } - - return ParseResult(result); - } - }; - -} diff --git a/kernel/include/kernel/ACPI/AML/Integer.h b/kernel/include/kernel/ACPI/AML/Integer.h deleted file mode 100644 index b2942b24..00000000 --- a/kernel/include/kernel/ACPI/AML/Integer.h +++ /dev/null @@ -1,39 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include - -namespace Kernel::ACPI::AML -{ - - struct Integer final : public AML::Node - { - struct Constants - { - // Initialized in Namespace::create_root_namespace - static BAN::RefPtr Zero; - static BAN::RefPtr One; - static BAN::RefPtr Ones; - }; - - uint64_t value; - const bool constant; - - Integer(uint64_t value, bool constant = false); - - BAN::Optional logical_compare(BAN::RefPtr node, AML::Byte binaryop); - - BAN::RefPtr convert(uint8_t mask) override; - BAN::RefPtr copy() override; - BAN::RefPtr store(BAN::RefPtr store_node) override; - - static ParseResult parse(BAN::ConstByteSpan& aml_data); - - void debug_print(int indent) const override; - }; - -} diff --git a/kernel/include/kernel/ACPI/AML/Method.h b/kernel/include/kernel/ACPI/AML/Method.h deleted file mode 100644 index f5ece4a5..00000000 --- a/kernel/include/kernel/ACPI/AML/Method.h +++ /dev/null @@ -1,182 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include - -namespace Kernel::ACPI::AML -{ - - struct Method final : public AML::Scope - { - Kernel::Mutex mutex; - uint8_t arg_count; - bool serialized; - uint8_t sync_level; - - BAN::Function(ParseContext&)> override_function; - BAN::ConstByteSpan term_list; - - Method(AML::NameSeg name, uint8_t arg_count, bool serialized, uint8_t sync_level) - : AML::Scope(Node::Type::Method, name) - , arg_count(arg_count) - , serialized(serialized) - , sync_level(sync_level) - {} - - BAN::RefPtr convert(uint8_t) override { return {}; } - - static ParseResult parse(AML::ParseContext& context) - { - ASSERT(context.aml_data.size() >= 1); - ASSERT(static_cast(context.aml_data[0]) == Byte::MethodOp); - context.aml_data = context.aml_data.slice(1); - - auto method_pkg = AML::parse_pkg(context.aml_data); - if (!method_pkg.has_value()) - return ParseResult::Failure; - - auto name_string = AML::NameString::parse(method_pkg.value()); - if (!name_string.has_value()) - return ParseResult::Failure; - - if (method_pkg->size() < 1) - return ParseResult::Failure; - auto method_flags = method_pkg.value()[0]; - method_pkg = method_pkg.value().slice(1); - - auto method = MUST(BAN::RefPtr::create( - name_string.value().path.back(), - method_flags & 0x07, - (method_flags >> 3) & 0x01, - method_flags >> 4 - )); - if (!Namespace::root_namespace()->add_named_object(context, name_string.value(), method)) - return ParseResult::Success; - method->term_list = method_pkg.value(); - -#if AML_DEBUG_LEVEL >= 2 - method->debug_print(0); - AML_DEBUG_PRINTLN(""); -#endif - - return ParseResult::Success; - } - - BAN::Optional> invoke( - BAN::RefPtr arg0 = {}, - BAN::RefPtr arg1 = {}, - BAN::RefPtr arg2 = {}, - BAN::RefPtr arg3 = {}, - BAN::RefPtr arg4 = {}, - BAN::RefPtr arg5 = {}, - BAN::RefPtr arg6 = {} - ) - { - BAN::Vector sync_stack; - return invoke_with_sync_stack(sync_stack, arg0, arg1, arg2, arg3, arg4, arg5, arg6); - } - - BAN::Optional> invoke_with_sync_stack( - BAN::Vector& current_sync_stack, - BAN::RefPtr arg0 = {}, - BAN::RefPtr arg1 = {}, - BAN::RefPtr arg2 = {}, - BAN::RefPtr arg3 = {}, - BAN::RefPtr arg4 = {}, - BAN::RefPtr arg5 = {}, - BAN::RefPtr arg6 = {} - ) - { - if (serialized && !current_sync_stack.empty() && sync_level < current_sync_stack.back()) - { - AML_ERROR("Trying to evaluate method {} with lower sync level than current sync level", scope); - return {}; - } - - ParseContext context; - context.aml_data = term_list; - context.scope = scope; - context.method_args[0] = MUST(BAN::RefPtr::create(arg0)); - context.method_args[1] = MUST(BAN::RefPtr::create(arg1)); - context.method_args[2] = MUST(BAN::RefPtr::create(arg2)); - context.method_args[3] = MUST(BAN::RefPtr::create(arg3)); - context.method_args[4] = MUST(BAN::RefPtr::create(arg4)); - context.method_args[5] = MUST(BAN::RefPtr::create(arg5)); - context.method_args[6] = MUST(BAN::RefPtr::create(arg6)); - context.sync_stack = BAN::move(current_sync_stack); - for (auto& local : context.method_locals) - local = MUST(BAN::RefPtr::create()); - - if (serialized) - { - mutex.lock(); - MUST(context.sync_stack.push_back(sync_level)); - } - -#if AML_DEBUG_LEVEL >= 2 - AML_DEBUG_PRINTLN("Evaluating {}", scope); -#endif - - BAN::Optional> return_value = BAN::RefPtr(); - - if (override_function) - return_value = override_function(context); - else - { - while (context.aml_data.size() > 0) - { - auto parse_result = AML::parse_object(context); - if (parse_result.returned()) - { - return_value = parse_result.node(); - break; - } - if (!parse_result.success()) - { - AML_ERROR("Method {} evaluate failed", scope); - return_value = {}; - break; - } - } - } - - if (return_value.has_value() && return_value.value() && return_value.value()->type == AML::Node::Type::Register) - return_value.value() = static_cast(return_value.value().ptr())->value; - - while (!context.created_objects.empty()) - { - Namespace::root_namespace()->remove_named_object(context.created_objects.back()); - context.created_objects.pop_back(); - } - - if (serialized) - { - context.sync_stack.pop_back(); - mutex.unlock(); - } - - current_sync_stack = BAN::move(context.sync_stack); - - return return_value; - } - - virtual void debug_print(int indent) const override - { - AML_DEBUG_PRINT_INDENT(indent); - AML_DEBUG_PRINT("Method "); - name.debug_print(); - AML_DEBUG_PRINTLN("({} args, {}Serialized, 0x{H}) {", arg_count, serialized ? "" : "Not", sync_level); - AML_DEBUG_PRINT_INDENT(indent + 1); - AML_DEBUG_PRINTLN("TermList: {} bytes", term_list.size()); - AML_DEBUG_PRINT_INDENT(indent); - AML_DEBUG_PRINT("}"); - } - }; - -} diff --git a/kernel/include/kernel/ACPI/AML/Mutex.h b/kernel/include/kernel/ACPI/AML/Mutex.h deleted file mode 100644 index 95827dd7..00000000 --- a/kernel/include/kernel/ACPI/AML/Mutex.h +++ /dev/null @@ -1,170 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include - -namespace Kernel::ACPI::AML -{ - - struct Mutex final : public AML::NamedObject - { - Kernel::Mutex mutex; - uint8_t sync_level; - bool global; - - Mutex(NameSeg name, uint8_t sync_level, bool global = false) - : NamedObject(Node::Type::Mutex, name) - , sync_level(sync_level) - , global(global) - {} - - BAN::RefPtr convert(uint8_t) override { return {}; } - - static ParseResult parse(ParseContext& context) - { - ASSERT(context.aml_data.size() >= 2); - ASSERT(static_cast(context.aml_data[0]) == AML::Byte::ExtOpPrefix); - - switch (static_cast(context.aml_data[1])) - { - case AML::ExtOp::MutexOp: - return parse_mutex(context); - case AML::ExtOp::AcquireOp: - return parse_acquire(context); - case AML::ExtOp::ReleaseOp: - return parse_release(context); - default: - ASSERT_NOT_REACHED(); - } - } - - virtual void debug_print(int indent) const override - { - AML_DEBUG_PRINT_INDENT(indent); - AML_DEBUG_PRINT("Mutex "); - name.debug_print(); - AML_DEBUG_PRINT(" (SyncLevel: {})", sync_level); - } - - private: - static ParseResult parse_mutex(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::MutexOp); - context.aml_data = context.aml_data.slice(2); - - auto name = NameString::parse(context.aml_data); - if (!name.has_value()) - return ParseResult::Failure; - - if (context.aml_data.size() < 1) - return ParseResult::Failure; - auto sync_level = context.aml_data[0]; - context.aml_data = context.aml_data.slice(1); - - if (sync_level & 0xF0) - { - AML_ERROR("Invalid sync level {}", sync_level); - return ParseResult::Failure; - } - - auto mutex = MUST(BAN::RefPtr::create(name->path.back(), sync_level)); - if (!Namespace::root_namespace()->add_named_object(context, name.value(), mutex)) - return ParseResult::Success; - -#if AML_DEBUG_LEVEL >= 2 - mutex->debug_print(0); - AML_DEBUG_PRINTLN(""); -#endif - - return ParseResult::Success; - } - - static ParseResult parse_acquire(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::AcquireOp); - context.aml_data = context.aml_data.slice(2); - - auto mutex_result = AML::parse_object(context); - if (!mutex_result.success() || !mutex_result.node() || mutex_result.node()->type != AML::Node::Type::Mutex) - { - AML_ERROR("Acquire does not name a valid mutex"); - return ParseResult::Failure; - } - - auto* mutex = static_cast(mutex_result.node().ptr()); - if (mutex->sync_level < context.sync_level()) - { - AML_ERROR("Trying to acquire mutex with lower sync level than current sync level"); - return ParseResult::Failure; - } - - if (context.aml_data.size() < 2) - { - AML_ERROR("Missing timeout value"); - return ParseResult::Failure; - } - uint16_t timeout = context.aml_data[0] | (context.aml_data[1] << 8); - context.aml_data = context.aml_data.slice(2); - - if (timeout >= 0xFFFF) - mutex->mutex.lock(); - else - { - // FIXME: This is a very inefficient way to wait for a mutex - uint64_t wake_time = SystemTimer::get().ms_since_boot() + timeout; - while (!mutex->mutex.try_lock()) - { - if (SystemTimer::get().ms_since_boot() >= wake_time) - return ParseResult(Integer::Constants::Ones); - Processor::yield(); - } - } - - MUST(context.sync_stack.push_back(mutex->sync_level)); - return ParseResult(Integer::Constants::Zero); - } - - static ParseResult parse_release(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::ReleaseOp); - context.aml_data = context.aml_data.slice(2); - - auto mutex_result = AML::parse_object(context); - if (!mutex_result.success() || !mutex_result.node() || mutex_result.node()->type != AML::Node::Type::Mutex) - { - AML_ERROR("Release does not name a valid mutex"); - return ParseResult::Failure; - } - - if (context.sync_stack.empty()) - { - AML_ERROR("Trying to release mutex without having acquired it"); - return ParseResult::Failure; - } - - auto* mutex = static_cast(mutex_result.node().ptr()); - if (mutex->sync_level != context.sync_level()) - { - AML_ERROR("Trying to release mutex with different sync level than current sync level"); - return ParseResult::Failure; - } - - mutex->mutex.unlock(); - context.sync_stack.pop_back(); - - return ParseResult::Success; - } - - }; - -} diff --git a/kernel/include/kernel/ACPI/AML/NamedObject.h b/kernel/include/kernel/ACPI/AML/NamedObject.h deleted file mode 100644 index e617ad0e..00000000 --- a/kernel/include/kernel/ACPI/AML/NamedObject.h +++ /dev/null @@ -1,44 +0,0 @@ -#pragma once - -#include -#include - -namespace Kernel::ACPI::AML -{ - - struct NamedObject : public AML::Node - { - BAN::RefPtr parent; - NameSeg name; - - NamedObject(Node::Type type, NameSeg name) : Node(type), name(name) {} - }; - - struct Name final : public AML::NamedObject - { - BAN::RefPtr object; - - Name(NameSeg name, BAN::RefPtr object) - : NamedObject(Node::Type::Name, name), object(BAN::move(object)) - {} - - BAN::RefPtr to_underlying() override { return object; } - - BAN::RefPtr convert(uint8_t mask) override - { - ASSERT(object); - return object->convert(mask); - } - - BAN::RefPtr store(BAN::RefPtr node) override - { - ASSERT(object); - ASSERT(object->type != AML::Node::Type::Reference); - return object->store(node); - } - - static ParseResult parse(ParseContext& context); - virtual void debug_print(int indent) const override; - }; - -} diff --git a/kernel/include/kernel/ACPI/AML/Names.h b/kernel/include/kernel/ACPI/AML/Names.h deleted file mode 100644 index 4041c0e7..00000000 --- a/kernel/include/kernel/ACPI/AML/Names.h +++ /dev/null @@ -1,244 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include - -namespace Kernel::ACPI::AML -{ - - struct NameSeg - { - union { - char chars[4]; - uint32_t u32; - }; - - NameSeg() = default; - - NameSeg(BAN::StringView name) - { - ASSERT(name.size() <= 4); - for (size_t i = 0; i < name.size(); i++) - chars[i] = static_cast(name[i]); - for (size_t i = name.size(); i < 4; i++) - chars[i] = '_'; - } - - NameSeg(BAN::ConstByteSpan& aml_data) - { - ASSERT(aml_data.size() >= 4); - for (size_t i = 0; i < 4; i++) - chars[i] = static_cast(aml_data[i]); - aml_data = aml_data.slice(4); - } - - BAN::StringView sv() const - { - size_t len = 4; - while (len > 0 && chars[len - 1] == '_') - len--; - return BAN::StringView(chars, len); - } - - static BAN::Optional parse(BAN::ConstByteSpan& aml_data) - { - if (aml_data.size() < 4) - return {}; - - if (!is_lead_name_char(aml_data[0]) - || !is_name_char(aml_data[1]) - || !is_name_char(aml_data[2]) - || !is_name_char(aml_data[3])) - return {}; - - return NameSeg(aml_data); - } - - constexpr bool operator==(const NameSeg& other) const - { - return u32 == other.u32; - } - - void debug_print() const - { - size_t len = 4; - while (len > 0 && chars[len - 1] == '_') - len--; - for (size_t i = 0; i < len; i++) - AML_DEBUG_PUTC(chars[i]); - } - }; - - struct NameString - { - BAN::String prefix; - BAN::Vector path; - - NameString() = default; - NameString(BAN::StringView str) - { - if (!str.empty() && str.front() == '\\') - { - MUST(prefix.push_back('\\')); - str = str.substring(1); - } - else - { - while (str.size() > 0 && str.front() == '^') - { - MUST(prefix.push_back('^')); - str = str.substring(1); - } - } - - while (!str.empty()) - { - ASSERT(str[0] != '.'); - size_t len = 1; - while (len < str.size() && str[len] != '.') - len++; - ASSERT(len <= 4); - - MUST(path.push_back(NameSeg(str.substring(0, len)))); - str = str.substring(len); - - if (!str.empty()) - { - ASSERT(str[0] == '.'); - str = str.substring(1); - } - } - } - - static bool can_parse(BAN::ConstByteSpan aml_data) - { - if (aml_data.size() == 0) - return false; - switch (static_cast(aml_data[0])) - { - case AML::Byte::RootChar: - case AML::Byte::ParentPrefixChar: - case AML::Byte::NullName: - case AML::Byte::DualNamePrefix: - case AML::Byte::MultiNamePrefix: - return true; - default: - return is_lead_name_char(aml_data[0]); - } - } - - static BAN::Optional parse(BAN::ConstByteSpan& aml_data) - { - if (aml_data.size() == 0) - return {}; - - NameString result; - - if (static_cast(aml_data[0]) == AML::Byte::RootChar) - { - MUST(result.prefix.push_back('\\')); - aml_data = aml_data.slice(1); - } - else - { - while (aml_data.size() > 0 && static_cast(aml_data[0]) == AML::Byte::ParentPrefixChar) - { - MUST(result.prefix.push_back(aml_data[0])); - aml_data = aml_data.slice(1); - } - } - - if (aml_data.size() == 0) - return {}; - - size_t name_count = 1; - switch (static_cast(aml_data[0])) - { - case AML::Byte::NullName: - name_count = 0; - aml_data = aml_data.slice(1); - break; - case AML::Byte::DualNamePrefix: - name_count = 2; - aml_data = aml_data.slice(1); - break; - case AML::Byte::MultiNamePrefix: - if (aml_data.size() < 2) - return {}; - name_count = aml_data[1]; - aml_data = aml_data.slice(2); - break; - default: - break; - } - - for (size_t i = 0; i < name_count; i++) - { - auto name_seg = NameSeg::parse(aml_data); - if (!name_seg.has_value()) - return {}; - MUST(result.path.push_back(name_seg.release_value())); - } - - return result; - } - - void debug_print() const - { - for (size_t i = 0; i < prefix.size(); i++) - AML_DEBUG_PUTC(prefix[i]); - if (!path.empty()) - path.front().debug_print(); - for (size_t i = 1; i < path.size(); i++) - { - AML_DEBUG_PUTC('.'); - path[i].debug_print(); - } - } - }; - -} - -namespace BAN -{ - - template<> - struct hash - { - constexpr hash_t operator()(Kernel::ACPI::AML::NameSeg name) const - { - return hash()(name.u32); - } - }; - - namespace Formatter - { - template - void print_argument(F putc, const Kernel::ACPI::AML::NameSeg& name_seg, const ValueFormat&) - { - size_t len = 4; - while (len > 0 && name_seg.chars[len - 1] == '_') - len--; - for (size_t i = 0; i < len; i++) - putc(name_seg.chars[i]); - } - - template - void print_argument(F putc, const Kernel::ACPI::AML::NameString& name_string, const ValueFormat&) - { - print_argument(putc, name_string.prefix, {}); - if (!name_string.path.empty()) - print_argument(putc, name_string.path.front(), {}); - for (size_t i = 1; i < name_string.path.size(); i++) - { - putc('.'); - print_argument(putc, name_string.path[i], {}); - } - } - } - -} diff --git a/kernel/include/kernel/ACPI/AML/Namespace.h b/kernel/include/kernel/ACPI/AML/Namespace.h index 85030167..352b67d7 100644 --- a/kernel/include/kernel/ACPI/AML/Namespace.h +++ b/kernel/include/kernel/ACPI/AML/Namespace.h @@ -1,66 +1,64 @@ #pragma once +#include +#include +#include #include -#include -#include -#include +#include + +#include namespace Kernel::ACPI::AML { - struct Namespace final : public AML::Scope + struct Namespace { - static BAN::RefPtr create_root_namespace(); - static BAN::RefPtr root_namespace(); - static BAN::RefPtr debug_node; + BAN_NON_COPYABLE(Namespace); + BAN_NON_MOVABLE(Namespace); + public: + Namespace() = default; + ~Namespace(); - template - static void for_each_child(const AML::NameString& scope, const F& callback) + static BAN::ErrorOr initialize_root_namespace(); + static Namespace& root_namespace(); + + // this has to be called after initalizing ACPI namespace + BAN::ErrorOr initalize_op_regions(); + + BAN::ErrorOr parse(BAN::ConstByteSpan); + + BAN::ErrorOr evaluate(BAN::StringView); + + // returns empty scope if object already exited + BAN::ErrorOr add_named_object(const Scope& scope, const NameString& name_string, Node&& node); + BAN::ErrorOr add_named_object(const Scope& scope, const NameString& name_string, Reference* reference); + + BAN::ErrorOr remove_named_object(const Scope& absolute_path); + + BAN::ErrorOr initialize_devices(); + + // node is nullptr if it is not found + struct FindResult { - auto canonical_path = root_namespace()->resolve_path(scope, {}, FindMode::ForceAbsolute); - ASSERT(canonical_path.has_value()); - - for (auto& [path, child] : root_namespace()->m_objects) - { - if (path.size() < canonical_path->size() + 1) - continue; - if (canonical_path->size() != 1 && path[canonical_path->size()] != '.') - continue; - if (path.sv().substring(0, canonical_path->size()) != canonical_path->sv()) - continue; - if (path.sv().substring(canonical_path->size() + 1).contains('.')) - continue; - callback(path, child); - } - } - - Namespace(NameSeg name) : AML::Scope(Node::Type::Namespace, name) {} - - BAN::RefPtr convert(uint8_t) override { return {}; } - - bool parse(const SDTHeader& header); - - void debug_print(int indent) const override; - - enum class FindMode - { - Normal, - ForceAbsolute, + Scope path; + Reference* node { nullptr }; }; - BAN::Optional resolve_path(const AML::NameString& relative_base, const AML::NameString& relative_path, FindMode mode, bool check_existence = true) const; + BAN::ErrorOr find_named_object(const Scope& scope, const NameString& name_string, bool force_absolute = false); - // Find an object in the namespace. Returns nullptr if the object is not found. - BAN::RefPtr find_object(const AML::NameString& relative_base, const AML::NameString& relative_path, FindMode mode); - - // Add an object to the namespace. Returns false if the parent object could not be added. - bool add_named_object(ParseContext&, const AML::NameString& object_path, BAN::RefPtr object); - - // Remove an object from the namespace. Returns false if the object could not be removed. - bool remove_named_object(const AML::NameString& absolute_path); + BAN::ErrorOr for_each_child(const Scope&, const BAN::Function&); + BAN::ErrorOr for_each_child(const Scope&, const BAN::Function&); private: - BAN::HashMap> m_objects; - mutable Mutex m_object_mutex; + BAN::ErrorOr resolve_path(const Scope& scope, const NameString& name_string); + + BAN::ErrorOr initialize_scope(const Scope& scope); + + BAN::ErrorOr opregion_call_reg(const Scope& scope, const Node& opregion); + + private: + bool m_has_parsed_namespace { false }; + BAN::HashMap m_named_objects; + BAN::HashMap m_called_reg_bitmaps; }; } diff --git a/kernel/include/kernel/ACPI/AML/Node.h b/kernel/include/kernel/ACPI/AML/Node.h index 71566a7d..92d35b18 100644 --- a/kernel/include/kernel/ACPI/AML/Node.h +++ b/kernel/include/kernel/ACPI/AML/Node.h @@ -1,115 +1,419 @@ #pragma once +#include #include +#include +#include #include -#include +#include #include -#include + +#include +#include +#include + +#define AML_DUMP_FUNCTION_CALLS 0 +#define AML_ENABLE_DEBUG 1 namespace Kernel::ACPI::AML { - struct Buffer; - struct Integer; - struct String; - - struct Node : public BAN::RefCounted + struct NameString { - static uint64_t total_node_count; - - enum Conversion : uint8_t + BAN_NON_COPYABLE(NameString); + public: + NameString() = default; + NameString(NameString&& other) + : parts(BAN::move(other.parts)) + {} + NameString& operator=(NameString&& other) { - ConvBuffer = 1 << 0, - ConvBufferField = 1 << 1, - ConvFieldUnit = 1 << 2, - ConvInteger = 1 << 3, - ConvString = 1 << 4, + parts = BAN::move(other.parts); + return *this; + } + + static BAN::ErrorOr from_string(BAN::StringView name); + + BAN::ErrorOr copy() const + { + NameString result; + result.base = this->base; + + TRY(result.parts.resize(parts.size())); + for (size_t i = 0; i < parts.size(); i++) + result.parts[i] = parts[i]; + + return result; + } + + static constexpr uint32_t base_root = -1; + uint32_t base { 0 }; + BAN::Vector parts; + }; + + template + struct Pair + { + T1 elem1; + T2 elem2; + }; + + struct Node; + struct ParseContext; + struct Reference; + + struct Mutex + { + Kernel::Mutex mutex; + uint8_t sync_level; + bool global_lock; + uint32_t ref_count; + }; + + struct Buffer + { + uint64_t size; + uint32_t ref_count; + uint8_t bytes[]; + }; + + struct OpRegion + { + GAS::AddressSpaceID address_space; + uint64_t offset; + uint64_t length; + }; + + struct FieldUnit + { + enum class Type { + Field, + IndexField, + BankField, + }; + uint64_t offset; + uint64_t length; + uint8_t flags; + Type type; + + union { + struct { + OpRegion opregion; + } field; + struct { + Reference* index; + Reference* data; + } index_field; + struct { + OpRegion opregion; + Reference* bank_selector; + uint64_t bank_value; + } bank_field; + } as; + }; + + struct Package + { + struct Element + { + struct Location { + NameString name; + Scope scope; + }; + + bool resolved { true }; + union { + Node* node { nullptr }; + Location* location; + } value; }; - enum class Type : uint8_t + uint64_t num_elements; + uint32_t ref_count; + Element elements[]; + }; + + struct Node + { + BAN_NON_COPYABLE(Node); + public: + Node() = default; + ~Node() { clear(); } + + Node(Node&& other) { *this = BAN::move(other); } + Node& operator=(Node&&); + + enum class Type { - None, - BankFieldElement, - Buffer, - BufferField, + Uninitialized, Debug, - Device, - Event, - FieldElement, - IndexFieldElement, Integer, + String, + Buffer, + Package, + BufferField, + OpRegion, + FieldUnit, + Event, + Device, + Processor, + PowerResource, + ThermalZone, Method, Mutex, - Name, - Namespace, - OpRegion, - Package, - PackageElement, - PowerResource, - Processor, + // FIXME: Index should not be its own type + // parsing index should return references + Index, Reference, - Register, - String, - ThermalZone, - }; - const Type type; + PredefinedScope, + Count + } type { Type::Uninitialized }; - Node(Type type) : type(type) { total_node_count++; } - virtual ~Node() { total_node_count--; } + inline bool is_scope() const + { + switch (type) + { + case Type::Device: + case Type::Processor: + case Type::PowerResource: + case Type::ThermalZone: + case Type::PredefinedScope: + return true; + default: + return false; + } + ASSERT_NOT_REACHED(); + } - virtual bool is_scope() const { return false; } + union + { + struct { + uint64_t value; + } integer; + Package* package; + Buffer* str_buf; + struct { + Buffer* buffer; + uint64_t bit_offset; + uint64_t bit_count; + } buffer_field; + OpRegion opregion; + FieldUnit field_unit; + struct { + uint32_t signal_count; + } event; + struct { + uint8_t storage[sizeof(Kernel::Mutex)]; + const uint8_t* start; + size_t length; + uint8_t arg_count; + BAN::ErrorOr (*override_func)(const BAN::Array&); + bool serialized; + Mutex* mutex; + } method; + Mutex* mutex; + struct { + Node::Type type; + union { + Buffer* str_buf; + Package* package; + } as; + uint64_t index; + } index; + Reference* reference; + } as; - [[nodiscard]] virtual BAN::RefPtr to_underlying() { return this; } - [[nodiscard]] virtual BAN::RefPtr convert(uint8_t mask) = 0; - [[nodiscard]] virtual BAN::RefPtr copy() { return this; } - [[nodiscard]] virtual BAN::RefPtr store(BAN::RefPtr) { AML_TODO("store, type {}", static_cast(type)); return {}; } + BAN::ErrorOr copy() const; - virtual void debug_print(int indent) const = 0; + void clear(); }; - struct ParseContext; - struct ParseResult + struct Reference { - static ParseResult Failure; - static ParseResult Success; - - enum class Result - { - Success, - Failure, - Returned, - Breaked, - Continued, - }; - - ParseResult(Result success) - : m_result(success) - {} - ParseResult(Result success, BAN::RefPtr node) - : m_result(success) - , m_node(BAN::move(node)) - {} - ParseResult(BAN::RefPtr node) - : m_result(Result::Success) - , m_node(BAN::move(node)) - { - ASSERT(m_node); - } - - bool success() const { return m_result == Result::Success; } - bool returned() const { return m_result == Result::Returned; } - bool breaked() const { return m_result == Result::Breaked; } - bool continued() const { return m_result == Result::Continued; } - - BAN::RefPtr node() - { - return m_node; - } - - private: - Result m_result = Result::Failure; - BAN::RefPtr m_node; + Node node {}; + uint32_t ref_count { 1 }; }; - ParseResult parse_object(ParseContext& context); + + struct ParseContext + { + Scope scope; + BAN::ConstByteSpan aml_data; + + uint32_t call_depth { 0 }; + BAN::Array locals; + BAN::Array args; + + BAN::LinkedList created_nodes; + + ~ParseContext(); + BAN::ErrorOr allocate_locals(); + }; + + enum class ExecutionFlow + { + Normal, + Break, + Continue, + Return, + }; + using ExecutionFlowResult = Pair>; + + enum Conversion : uint8_t + { + ConvInteger = 1, + ConvBuffer = 2, + ConvString = 4, + }; + + BAN::ErrorOr parse_node(ParseContext& context, bool return_ref = false); + BAN::ErrorOr parse_node_or_execution_flow(ParseContext& context); + + BAN::ErrorOr parse_name_string(BAN::ConstByteSpan& aml_data); + BAN::ErrorOr parse_pkg(BAN::ConstByteSpan& aml_data); + + BAN::ErrorOr convert_node(Node&& source, uint8_t conversion, size_t max_length); + BAN::ErrorOr convert_node(Node&& source, const Node& target); + + BAN::ErrorOr evaluate_node(const Scope& node_path, const Node& node); + + // If method has no return, it will return + BAN::ErrorOr method_call(const Scope& scope, const Node& method, BAN::Array&& args, uint32_t call_depth = 0); + +} + +namespace BAN::Formatter +{ + + template + void print_argument(F putc, const Kernel::ACPI::AML::NameString& name_string, const ValueFormat&) + { + if (name_string.base == Kernel::ACPI::AML::NameString::base_root) + putc('\\'); + else for (uint32_t i = 0; i < name_string.base; i++) + putc('^'); + for (size_t i = 0; i < name_string.parts.size(); i++) { + if (i != 0) + putc('.'); + const char* name_seg = reinterpret_cast(&name_string.parts[i]); + putc(name_seg[0]); putc(name_seg[1]); putc(name_seg[2]); putc(name_seg[3]); + } + } + + template + void print_argument(F putc, const Kernel::ACPI::AML::Buffer& buffer, const ValueFormat&) + { + static constexpr size_t max_elements { 16 }; + + print(putc, " max_elements) + print(putc, "..."); + print(putc, "'>"); + } + + template + void print_argument(F putc, const Kernel::ACPI::AML::Package& package, const ValueFormat&) + { + print(putc, "", package.num_elements); + } + + template + void print_argument(F putc, const Kernel::ACPI::AML::Node& node, const ValueFormat&) + { + switch (node.type) + { + case Kernel::ACPI::AML::Node::Type::Uninitialized: + print(putc, ""); + break; + case Kernel::ACPI::AML::Node::Type::Debug: + print(putc, ""); + break; + case Kernel::ACPI::AML::Node::Type::Integer: + print(putc, "", node.as.integer.value); + break; + case Kernel::ACPI::AML::Node::Type::String: + print(putc, "", + BAN::StringView( + reinterpret_cast(node.as.str_buf->bytes), + node.as.str_buf->size + ) + ); + break; + case Kernel::ACPI::AML::Node::Type::Package: + print(putc, "{}", *node.as.package); + break; + case Kernel::ACPI::AML::Node::Type::Buffer: + print(putc, "{}", *node.as.str_buf); + break; + case Kernel::ACPI::AML::Node::Type::BufferField: + print(putc, "", + node.as.buffer_field.buffer->size, + node.as.buffer_field.bit_offset, + node.as.buffer_field.bit_count + ); + break; + case Kernel::ACPI::AML::Node::Type::OpRegion: + print(putc, "", + static_cast(node.as.opregion.address_space), + node.as.opregion.offset, + node.as.opregion.length + ); + break; + case Kernel::ACPI::AML::Node::Type::FieldUnit: + print(putc, "", + static_cast(node.as.field_unit.type), + node.as.field_unit.offset, + node.as.field_unit.length + ); + break; + case Kernel::ACPI::AML::Node::Type::Event: + print(putc, "", node.as.event.signal_count); + break; + case Kernel::ACPI::AML::Node::Type::Device: + print(putc, ""); + break; + case Kernel::ACPI::AML::Node::Type::Processor: + print(putc, ""); + break; + case Kernel::ACPI::AML::Node::Type::PowerResource: + print(putc, ""); + break; + case Kernel::ACPI::AML::Node::Type::ThermalZone: + print(putc, ""); + break; + case Kernel::ACPI::AML::Node::Type::Method: + print(putc, "", node.as.method.length); + break; + case Kernel::ACPI::AML::Node::Type::Mutex: + print(putc, ""); + break; + case Kernel::ACPI::AML::Node::Type::Index: + switch (node.as.index.type) + { + case Kernel::ACPI::AML::Node::Type::String: + case Kernel::ACPI::AML::Node::Type::Buffer: + print(putc, "", *node.as.index.as.str_buf, node.as.index.index); + break; + case Kernel::ACPI::AML::Node::Type::Package: + print(putc, "", *node.as.index.as.package, node.as.index.index); + break; + default: + print(putc, "", (uint32_t)node.as.index.type, node.as.index.index); + break; + } + break; + case Kernel::ACPI::AML::Node::Type::Reference: + print(putc, "", node.as.reference->node, node.as.reference->ref_count); + break; + case Kernel::ACPI::AML::Node::Type::PredefinedScope: + print(putc, ""); + break; + case Kernel::ACPI::AML::Node::Type::Count: + ASSERT_NOT_REACHED(); + } + } } diff --git a/kernel/include/kernel/ACPI/AML/Notify.h b/kernel/include/kernel/ACPI/AML/Notify.h deleted file mode 100644 index f75879e2..00000000 --- a/kernel/include/kernel/ACPI/AML/Notify.h +++ /dev/null @@ -1,67 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -namespace Kernel::ACPI::AML -{ - - struct Notify - { - static ParseResult parse(ParseContext& context) - { - ASSERT(context.aml_data.size() >= 1); - ASSERT(static_cast(context.aml_data[0]) == Byte::NotifyOp); - context.aml_data = context.aml_data.slice(1); - - auto object_result = AML::parse_object(context); - if (!object_result.success()) - return ParseResult::Failure; - auto object = object_result.node(); - if (!object) - { - AML_ERROR("Notify object is null"); - return ParseResult::Failure; - } - - auto value_result = AML::parse_object(context); - if (!value_result.success()) - return ParseResult::Failure; - auto value_node = value_result.node() ? value_result.node()->convert(AML::Node::ConvInteger) : BAN::RefPtr(); - if (!value_node) - { - AML_ERROR("Notify value is not an integer"); - return ParseResult::Failure; - } - const auto value = static_cast(value_node.ptr())->value; - - BAN::StringView object_type_sv; - BAN::StringView object_name_sv; - switch (object->type) - { - case AML::Node::Type::Device: - object_type_sv = "Device"_sv; - object_name_sv = static_cast(object.ptr())->name.sv(); - break; - case AML::Node::Type::Processor: - object_type_sv = "Processor"_sv; - object_name_sv = static_cast(object.ptr())->name.sv(); - break; - case AML::Node::Type::ThermalZone: - object_type_sv = "ThermalZone"_sv; - object_name_sv = static_cast(object.ptr())->name.sv(); - break; - default: - object_type_sv = "Unknown"_sv; - object_name_sv = "????"_sv; - break; - } - - AML_TODO("Notify: {} {}: {2H}", object_type_sv, object_name_sv, value); - return ParseResult::Success; - } - }; - -} diff --git a/kernel/include/kernel/ACPI/AML/ObjectType.h b/kernel/include/kernel/ACPI/AML/ObjectType.h deleted file mode 100644 index 6949b817..00000000 --- a/kernel/include/kernel/ACPI/AML/ObjectType.h +++ /dev/null @@ -1,107 +0,0 @@ -#pragma once - -#include -#include -#include - -namespace Kernel::ACPI::AML -{ - - struct ObjectType - { - static ParseResult parse(ParseContext& context) - { - ASSERT(context.aml_data.size() >= 1); - ASSERT(static_cast(context.aml_data[0]) == Byte::ObjectTypeOp); - context.aml_data = context.aml_data.slice(1); - - auto object_result = AML::parse_object(context); - if (!object_result.success()) - return ParseResult::Failure; - auto object = object_result.node() - ? object_result.node()->to_underlying() - : BAN::RefPtr(); - - if (object && object->type == AML::Node::Type::Reference) - object = static_cast(object.ptr())->node->to_underlying(); - - uint64_t value = 0; - if (object) - { - switch (object->type) - { - case AML::Node::Type::None: - case AML::Node::Type::Name: - case AML::Node::Type::PackageElement: - case AML::Node::Type::Reference: - case AML::Node::Type::Register: - ASSERT_NOT_REACHED(); - case AML::Node::Type::Namespace: - value = 0; - break; - case AML::Node::Type::Integer: - value = 1; - break; - case AML::Node::Type::String: - value = 2; - break; - case AML::Node::Type::Buffer: - value = 3; - break; - case AML::Node::Type::Package: - value = 4; - break; - case AML::Node::Type::FieldElement: - case AML::Node::Type::BankFieldElement: - case AML::Node::Type::IndexFieldElement: - value = 5; - break; - case AML::Node::Type::Device: - value = 6; - break; - case AML::Node::Type::Event: - value = 7; - break; - case AML::Node::Type::Method: - value = 8; - break; - case AML::Node::Type::Mutex: - value = 9; - break; - case AML::Node::Type::OpRegion: - value = 10; - break; - case AML::Node::Type::PowerResource: - value = 11; - break; - case AML::Node::Type::Processor: - value = 12; - break; - case AML::Node::Type::ThermalZone: - value = 13; - break; - case AML::Node::Type::BufferField: - value = 14; - break; - case AML::Node::Type::Debug: - value = 16; - break; - } - } - -#if AML_DEBUG_LEVEL >= 2 - if (!object) - AML_DEBUG_PRINTLN("ObjectType { null }"); - else - { - AML_DEBUG_PRINTLN("ObjectType {"); - object->debug_print(1); - AML_DEBUG_PRINTLN(""); - } -#endif - - return ParseResult(MUST(BAN::RefPtr::create(value))); - } - }; - -} diff --git a/kernel/include/kernel/ACPI/AML/OpRegion.h b/kernel/include/kernel/ACPI/AML/OpRegion.h new file mode 100644 index 00000000..c17d21c5 --- /dev/null +++ b/kernel/include/kernel/ACPI/AML/OpRegion.h @@ -0,0 +1,16 @@ +#pragma once + +#include + +namespace Kernel::ACPI::AML +{ + + BAN::ErrorOr parse_opregion_op(ParseContext& context); + BAN::ErrorOr parse_field_op(ParseContext& context); + BAN::ErrorOr parse_index_field_op(ParseContext& context); + BAN::ErrorOr parse_bank_field_op(ParseContext& context); + + BAN::ErrorOr convert_from_field_unit(const Node& node, uint8_t conversion, size_t max_length); + BAN::ErrorOr store_to_field_unit(const Node& source, const Node& target); + +} diff --git a/kernel/include/kernel/ACPI/AML/Package.h b/kernel/include/kernel/ACPI/AML/Package.h deleted file mode 100644 index d4354126..00000000 --- a/kernel/include/kernel/ACPI/AML/Package.h +++ /dev/null @@ -1,168 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include - -namespace Kernel::ACPI::AML -{ - - struct PackageElement; - - struct Package final : public AML::Node - { - BAN::Vector> elements; - AML::NameString scope; - - Package(AML::NameString scope) - : Node(Node::Type::Package) - , elements(BAN::move(elements)) - , scope(scope) - {} - - BAN::RefPtr convert(uint8_t) override { return {}; } - - static ParseResult parse(AML::ParseContext& context); - virtual void debug_print(int indent) const override; - }; - - struct PackageElement final : public AML::Node - { - BAN::RefPtr parent; - BAN::RefPtr element; - AML::NameString unresolved_name; - bool resolved = false; - bool initialized = false; - - PackageElement(BAN::RefPtr parent, BAN::RefPtr element) - : Node(Node::Type::PackageElement) - , parent(parent) - , element(element) - { - ASSERT(element); - resolved = true; - initialized = true; - } - - PackageElement(BAN::RefPtr parent, AML::NameString unresolved_name) - : Node(Node::Type::PackageElement) - , parent(parent) - , unresolved_name(unresolved_name) - { - resolved = false; - initialized = true; - } - - PackageElement(BAN::RefPtr parent) - : Node(Node::Type::PackageElement) - , parent(parent) - { - resolved = false; - initialized = false; - } - - bool resolve() - { - ASSERT(!resolved); - - auto object = Namespace::root_namespace()->find_object(parent->scope, unresolved_name, Namespace::FindMode::Normal); - if (!object) - { - AML_ERROR("Failed to resolve reference {} in package {}", unresolved_name, parent->scope); - return false; - } - element = object; - resolved = true; - - return true; - } - - BAN::RefPtr convert(uint8_t mask) override - { - if (!initialized) - { - AML_ERROR("Trying to convert uninitialized PackageElement"); - return {}; - } - if (!resolved && !resolve()) - return {}; - return element->convert(mask); - } - - BAN::RefPtr to_underlying() override - { - if (!initialized) - { - AML_ERROR("Trying to read uninitialized PackageElement"); - return {}; - } - if (!resolved && !resolve()) - return {}; - return element; - } - - BAN::RefPtr store(BAN::RefPtr node) override - { - if (!initialized) - { - initialized = true; - resolved = true; - } - if (!resolved && !resolve()) - return {}; - ASSERT(!element || element->type != AML::Node::Type::Reference); - if (node->type == AML::Node::Type::Reference) - element = static_cast(node.ptr())->node; - else - element = node->copy(); - return node; - } - - static ParseResult parse(AML::ParseContext& context, BAN::RefPtr package) - { - BAN::RefPtr element; - if (context.aml_data[0] != 0x00 && AML::NameString::can_parse(context.aml_data)) - { - auto name = AML::NameString::parse(context.aml_data); - if (!name.has_value()) - return ParseResult::Failure; - element = MUST(BAN::RefPtr::create(package, name.value())); - } - else - { - auto element_result = AML::parse_object(context); - if (!element_result.success()) - return ParseResult::Failure; - element = MUST(BAN::RefPtr::create(package, element_result.node())); - } - return ParseResult(element); - } - - virtual void debug_print(int indent) const override - { - AML_DEBUG_PRINT_INDENT(indent); - AML_DEBUG_PRINTLN("PackageElement {"); - if (!initialized) - { - AML_DEBUG_PRINT_INDENT(indent + 1); - AML_DEBUG_PRINT("Uninitialized"); - } - else if (!resolved) - { - AML_DEBUG_PRINT_INDENT(indent + 1); - AML_DEBUG_PRINT("Unresolved {}", unresolved_name); - } - else - { - element->debug_print(indent + 1); - } - AML_DEBUG_PRINTLN(""); - AML_DEBUG_PRINT_INDENT(indent); - AML_DEBUG_PRINT("}"); - } - }; - -} diff --git a/kernel/include/kernel/ACPI/AML/ParseContext.h b/kernel/include/kernel/ACPI/AML/ParseContext.h deleted file mode 100644 index c02daa46..00000000 --- a/kernel/include/kernel/ACPI/AML/ParseContext.h +++ /dev/null @@ -1,30 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include - -namespace Kernel::ACPI::AML -{ - - struct ParseContext - { - BAN::ConstByteSpan aml_data; - AML::NameString scope; - - // Used for cleaning up on method exit - // NOTE: This uses linked list instead of vector because - // we don't really need large contiguous memory - BAN::LinkedList created_objects; - - uint8_t sync_level() const { return !sync_stack.empty() ? sync_stack.back() : 0; } - BAN::Vector sync_stack; - - BAN::Array, 7> method_args; - BAN::Array, 8> method_locals; - }; - -} diff --git a/kernel/include/kernel/ACPI/AML/Pkg.h b/kernel/include/kernel/ACPI/AML/Pkg.h deleted file mode 100644 index a9898d98..00000000 --- a/kernel/include/kernel/ACPI/AML/Pkg.h +++ /dev/null @@ -1,51 +0,0 @@ -#pragma once - -#include -#include - -namespace Kernel::ACPI::AML -{ - - static BAN::Optional parse_pkg_length(BAN::ConstByteSpan aml_data) - { - if (aml_data.size() < 1) - return {}; - - uint8_t lead_byte = aml_data[0]; - if ((lead_byte & 0xC0) && (lead_byte & 0x30)) - return {}; - - uint32_t pkg_length = lead_byte & 0x3F; - uint8_t byte_count = (lead_byte >> 6) + 1; - - if (aml_data.size() < byte_count) - return {}; - - for (uint8_t i = 1; i < byte_count; i++) - pkg_length |= aml_data[i] << (i * 8 - 4); - - return pkg_length; - } - - static void trim_pkg_length(BAN::ConstByteSpan& aml_data) - { - ASSERT(aml_data.size() >= 1); - uint8_t byte_count = (aml_data[0] >> 6) + 1; - aml_data = aml_data.slice(byte_count); - } - - static BAN::Optional parse_pkg(BAN::ConstByteSpan& aml_data) - { - auto pkg_length = parse_pkg_length(aml_data); - if (!pkg_length.has_value()) - return {}; - - auto result = aml_data.slice(0, pkg_length.value()); - trim_pkg_length(result); - - aml_data = aml_data.slice(pkg_length.value()); - - return result; - } - -} diff --git a/kernel/include/kernel/ACPI/AML/PowerResource.h b/kernel/include/kernel/ACPI/AML/PowerResource.h deleted file mode 100644 index f7b27702..00000000 --- a/kernel/include/kernel/ACPI/AML/PowerResource.h +++ /dev/null @@ -1,70 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include - -namespace Kernel::ACPI::AML -{ - - struct PowerResource final : public AML::Scope - { - uint8_t system_level; - uint16_t resource_order; - - PowerResource(NameSeg name, uint8_t system_level, uint16_t resource_order) - : Scope(Node::Type::PowerResource, name) - , system_level(system_level) - , resource_order(resource_order) - {} - - BAN::RefPtr convert(uint8_t) override { return {}; } - - static ParseResult parse(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::PowerResOp); - context.aml_data = context.aml_data.slice(2); - - auto opt_power_res_pkg = AML::parse_pkg(context.aml_data); - if (!opt_power_res_pkg.has_value()) - return ParseResult::Failure; - auto power_res_pkg = opt_power_res_pkg.value(); - - auto name = NameString::parse(power_res_pkg); - if (!name.has_value()) - return ParseResult::Failure; - - if (power_res_pkg.size() < 1) - return ParseResult::Failure; - uint8_t system_level = power_res_pkg[0]; - power_res_pkg = power_res_pkg.slice(1); - - if (power_res_pkg.size() < 2) - return ParseResult::Failure; - uint16_t resource_order = BAN::little_endian_to_host(*reinterpret_cast(power_res_pkg.data())); - power_res_pkg = power_res_pkg.slice(2); - - auto power_res = MUST(BAN::RefPtr::create(name->path.back(), system_level, resource_order)); - if (!Namespace::root_namespace()->add_named_object(context, name.value(), power_res)) - return ParseResult::Failure; - -#if AML_DEBUG_LEVEL >= 2 - power_res->debug_print(0); - AML_DEBUG_PRINTLN(""); -#endif - - return power_res->enter_context_and_parse_term_list(context, name.value(), power_res_pkg); - } - - virtual void debug_print(int indent) const override - { - AML_DEBUG_PRINT_INDENT(indent); - AML_DEBUG_PRINT("PowerResource {} (SystemLevel {}, ResourceOrder {})", name, system_level, resource_order); - } - }; - -} diff --git a/kernel/include/kernel/ACPI/AML/Processor.h b/kernel/include/kernel/ACPI/AML/Processor.h deleted file mode 100644 index d4a55c66..00000000 --- a/kernel/include/kernel/ACPI/AML/Processor.h +++ /dev/null @@ -1,86 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include - -namespace Kernel::ACPI::AML -{ - - struct Processor final : public AML::Scope - { - uint8_t id; - uint32_t pblk_addr; - uint8_t pblk_len; - - Processor(NameSeg name, uint8_t id, uint32_t pblk_addr, uint8_t pblk_len) - : Scope(Node::Type::Processor, name) - , id(id) - , pblk_addr(pblk_addr) - , pblk_len(pblk_len) - {} - - BAN::RefPtr convert(uint8_t) override { return {}; } - - static ParseResult parse(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::ProcessorOp); - context.aml_data = context.aml_data.slice(2); - - auto opt_processor_pkg = AML::parse_pkg(context.aml_data); - if (!opt_processor_pkg.has_value()) - return ParseResult::Failure; - auto processor_pkg = opt_processor_pkg.value(); - - auto name = NameString::parse(processor_pkg); - if (!name.has_value()) - return ParseResult::Failure; - - if (processor_pkg.size() < 1) - return ParseResult::Failure; - uint8_t id = processor_pkg[0]; - processor_pkg = processor_pkg.slice(1); - - if (processor_pkg.size() < 4) - return ParseResult::Failure; - uint32_t pblk_addr = BAN::little_endian_to_host(*reinterpret_cast(processor_pkg.data())); - processor_pkg = processor_pkg.slice(4); - - if (processor_pkg.size() < 1) - return ParseResult::Failure; - uint8_t pblk_len = processor_pkg[0]; - processor_pkg = processor_pkg.slice(1); - - auto processor = MUST(BAN::RefPtr::create(name->path.back(), id, pblk_addr, pblk_len)); - if (!Namespace::root_namespace()->add_named_object(context, name.value(), processor)) - return ParseResult::Success; - -#if AML_DEBUG_LEVEL >= 2 - processor->debug_print(0); - AML_DEBUG_PRINTLN(""); -#endif - - return processor->enter_context_and_parse_term_list(context, name.value(), processor_pkg); - } - - virtual void debug_print(int indent) const override - { - AML_DEBUG_PRINT_INDENT(indent); - AML_DEBUG_PRINTLN("Processor {} (ID: {}, PBlkAddr: 0x{H}, PBlkLen: {}) {", name, id, pblk_addr, pblk_len); - Namespace::root_namespace()->for_each_child(scope, - [&](const auto&, const auto& child) - { - child->debug_print(indent + 1); - AML_DEBUG_PRINTLN(""); - } - ); - AML_DEBUG_PRINT_INDENT(indent); - AML_DEBUG_PRINT("}"); - } - }; - -} diff --git a/kernel/include/kernel/ACPI/AML/Reference.h b/kernel/include/kernel/ACPI/AML/Reference.h deleted file mode 100644 index 56a32a18..00000000 --- a/kernel/include/kernel/ACPI/AML/Reference.h +++ /dev/null @@ -1,186 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include - -namespace Kernel::ACPI::AML -{ - - struct Reference final : public AML::Node - { - BAN::RefPtr node; - - Reference(BAN::RefPtr node) - : Node(AML::Node::Type::Reference) - , node(node) - { - ASSERT(node); - } - - BAN::RefPtr convert(uint8_t mask) override - { - ASSERT(node); - return node->convert(mask); - } - - BAN::RefPtr store(BAN::RefPtr value) override - { - ASSERT(node); - return node->store(value); - } - - static ParseResult parse(ParseContext& context) - { - ASSERT(context.aml_data.size() >= 1); - - bool conditional = false; - switch (static_cast(context.aml_data[0])) - { - case AML::Byte::DerefOfOp: - return parse_dereference(context); - case AML::Byte::RefOfOp: - context.aml_data = context.aml_data.slice(1); - conditional = false; - break; - case AML::Byte::ExtOpPrefix: - ASSERT(static_cast(context.aml_data[1]) == AML::ExtOp::CondRefOfOp); - context.aml_data = context.aml_data.slice(2); - conditional = true; - break; - default: - ASSERT_NOT_REACHED(); - } - - BAN::RefPtr object; - if (NameString::can_parse(context.aml_data)) - { - auto name = NameString::parse(context.aml_data); - if (!name.has_value()) - return ParseResult::Failure; - object = Namespace::root_namespace()->find_object(context.scope, name.value(), Namespace::FindMode::Normal); - } - else - { - auto parse_result = AML::parse_object(context); - if (!parse_result.success()) - return ParseResult::Failure; - object = parse_result.node(); - } - - if (object && object->type == AML::Node::Type::Reference) - object = static_cast(object.ptr())->node; - if (object && object->type == AML::Node::Type::Register) - object = static_cast(object.ptr())->value; - - if (!conditional) - { - if (!object) - { - AML_ERROR("RefOf failed to resolve reference"); - return ParseResult::Failure; - } - auto reference = MUST(BAN::RefPtr::create(object)); -#if AML_DEBUG_LEVEL >= 2 - reference->debug_print(0); - AML_DEBUG_PRINTLN(""); -#endif - return ParseResult(reference); - } - - if (context.aml_data.size() < 1) - { - AML_ERROR("CondRefOf missing target"); - return ParseResult::Failure; - } - - BAN::RefPtr target_node; - if (context.aml_data[0] == 0x00) - context.aml_data = context.aml_data.slice(1); - else - { - auto target_result = AML::parse_object(context); - if (!target_result.success()) - return ParseResult::Failure; - target_node = target_result.node(); - if (!target_node) - { - AML_ERROR("CondRefOf failed to resolve target"); - return ParseResult::Failure; - } - } - -#if AML_DEBUG_LEVEL >= 2 - AML_DEBUG_PRINT("CondRefOf "); - if (object) - object->debug_print(0); - else - AML_DEBUG_PRINT("null"); - AML_DEBUG_PRINTLN(""); -#endif - - if (!object) - return AML::ParseResult(Integer::Constants::Zero); - - if (target_node && !target_node->store(object)) - { - AML_ERROR("CondRefOf failed to store into target"); - return ParseResult::Failure; - } - - return AML::ParseResult(Integer::Constants::Ones); - } - - static ParseResult parse_dereference(ParseContext& context) - { - ASSERT(context.aml_data.size() >= 1); - ASSERT(static_cast(context.aml_data[0]) == Byte::DerefOfOp); - context.aml_data = context.aml_data.slice(1); - - if (context.aml_data.size() >= 1 && static_cast(context.aml_data[0]) == AML::Byte::StringPrefix) - { - auto string_result = AML::String::parse(context); - if (!string_result.success()) - return ParseResult::Failure; - ASSERT(string_result.node()); - auto string = static_cast(string_result.node().ptr()); - AML_TODO("DerefOf String ({})", string->string); - return ParseResult::Failure; - } - else - { - auto parse_result = AML::parse_object(context); - if (!parse_result.success()) - return ParseResult::Failure; - auto node = parse_result.node(); - if (node && node->type == AML::Node::Type::Register) - node = static_cast(node.ptr())->value; - if (!node || node->type != AML::Node::Type::Reference) - { - AML_TODO("DerefOf source is not a Reference, but a {}", node ? static_cast(node->type) : 999); - return ParseResult::Failure; - } -#if AML_DEBUG_LEVEL >= 2 - AML_DEBUG_PRINT("DerefOf "); - node->debug_print(0); - AML_DEBUG_PRINTLN(""); -#endif - return ParseResult(static_cast(node.ptr())->node); - } - } - - virtual void debug_print(int indent) const override - { - AML_DEBUG_PRINT_INDENT(indent); - AML_DEBUG_PRINTLN("Reference {"); - node->debug_print(indent + 1); - AML_DEBUG_PRINTLN(""); - AML_DEBUG_PRINT_INDENT(indent); - AML_DEBUG_PRINT("}"); - } - }; - -} diff --git a/kernel/include/kernel/ACPI/AML/Region.h b/kernel/include/kernel/ACPI/AML/Region.h deleted file mode 100644 index 5080d51a..00000000 --- a/kernel/include/kernel/ACPI/AML/Region.h +++ /dev/null @@ -1,116 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -namespace Kernel::ACPI::AML -{ - - struct OpRegion final : public AML::NamedObject - { - using RegionSpace = GAS::AddressSpaceID; - RegionSpace region_space; - uint64_t region_offset; - uint64_t region_length; - - Kernel::Mutex mutex; - - OpRegion(NameSeg name, RegionSpace region_space, uint64_t region_offset, uint64_t region_length) - : NamedObject(Node::Type::OpRegion, name) - , region_space(region_space) - , region_offset(region_offset) - , region_length(region_length) - {} - - BAN::RefPtr convert(uint8_t) override { return {}; } - - static ParseResult parse(AML::ParseContext& context) - { - ASSERT(context.aml_data.size() > 2); - ASSERT(static_cast(context.aml_data[0]) == Byte::ExtOpPrefix); - ASSERT(static_cast(context.aml_data[1]) == ExtOp::OpRegionOp); - context.aml_data = context.aml_data.slice(2); - - auto name = NameString::parse(context.aml_data); - if (!name.has_value()) - return ParseResult::Failure; - - if (context.aml_data.size() < 1) - return ParseResult::Failure; - auto region_space = static_cast(context.aml_data[0]); - context.aml_data = context.aml_data.slice(1); - - auto offset_result = AML::parse_object(context); - if (!offset_result.success()) - return ParseResult::Failure; - auto offset_node = offset_result.node() - ? offset_result.node()->convert(AML::Node::ConvInteger) - : BAN::RefPtr(); - if (!offset_node) - { - AML_ERROR("OpRegion offset must be an integer"); - return ParseResult::Failure; - } - - auto length_result = AML::parse_object(context); - if (!length_result.success()) - return ParseResult::Failure; - auto length_node = length_result.node() - ? length_result.node()->convert(AML::Node::ConvInteger) - : BAN::RefPtr(); - if (!length_node) - { - AML_ERROR("OpRegion length must be an integer"); - return ParseResult::Failure; - } - - const auto offset = static_cast(offset_node.ptr())->value; - const auto length = static_cast(length_node.ptr())->value; - - auto op_region = MUST(BAN::RefPtr::create( - name->path.back(), - region_space, - offset, - length - )); - - if (!Namespace::root_namespace()->add_named_object(context, name.value(), op_region)) - return ParseResult::Success; - -#if AML_DEBUG_LEVEL >= 2 - op_region->debug_print(0); - AML_DEBUG_PRINTLN(""); -#endif - - return ParseResult::Success; - } - - virtual void debug_print(int indent) const override - { - BAN::StringView region_space_name; - switch (region_space) - { - case RegionSpace::SystemMemory: region_space_name = "SystemMemory"_sv; break; - case RegionSpace::SystemIO: region_space_name = "SystemIO"_sv; break; - case RegionSpace::PCIConfig: region_space_name = "PCIConfig"_sv; break; - case RegionSpace::EmbeddedController: region_space_name = "EmbeddedController"_sv; break; - case RegionSpace::SMBus: region_space_name = "SMBus"_sv; break; - case RegionSpace::SystemCMOS: region_space_name = "SystemCMOS"_sv; break; - case RegionSpace::PCIBarTarget: region_space_name = "PCIBarTarget"_sv; break; - case RegionSpace::IPMI: region_space_name = "IPMI"_sv; break; - case RegionSpace::GeneralPurposeIO: region_space_name = "GeneralPurposeIO"_sv; break; - case RegionSpace::GenericSerialBus: region_space_name = "GenericSerialBus"_sv; break; - case RegionSpace::PlatformCommunicationChannel: region_space_name = "PlatformCommunicationChannel"_sv; break; - default: region_space_name = "Unknown"_sv; break; - } - AML_DEBUG_PRINT_INDENT(indent); - AML_DEBUG_PRINT("OperationRegion("); - name.debug_print(); - AML_DEBUG_PRINT(", {}, 0x{H}, 0x{H})", region_space_name, region_offset, region_length); - } - - }; - -} diff --git a/kernel/include/kernel/ACPI/AML/Register.h b/kernel/include/kernel/ACPI/AML/Register.h deleted file mode 100644 index 40e7b307..00000000 --- a/kernel/include/kernel/ACPI/AML/Register.h +++ /dev/null @@ -1,23 +0,0 @@ -#pragma once - -#include - -namespace Kernel::ACPI::AML -{ - - struct Register final : public AML::Node - { - BAN::RefPtr value; - - Register(); - Register(BAN::RefPtr node); - - BAN::RefPtr to_underlying() override { return value->to_underlying(); } - - BAN::RefPtr convert(uint8_t mask) override; - BAN::RefPtr store(BAN::RefPtr source) override; - - void debug_print(int indent) const override; - }; - -} diff --git a/kernel/include/kernel/ACPI/AML/Scope.h b/kernel/include/kernel/ACPI/AML/Scope.h index 5e927145..b4a65eca 100644 --- a/kernel/include/kernel/ACPI/AML/Scope.h +++ b/kernel/include/kernel/ACPI/AML/Scope.h @@ -1,27 +1,76 @@ #pragma once -#include -#include +#include +#include +#include namespace Kernel::ACPI::AML { - struct Scope : public AML::NamedObject + struct Scope { - AML::NameString scope; + BAN_NON_COPYABLE(Scope); + public: + Scope() = default; + Scope(Scope&& other) { *this = BAN::move(other); } + Scope& operator=(Scope&& other) { parts = BAN::move(other.parts); return *this; } - Scope(Node::Type type, NameSeg name) - : NamedObject(type, name) - {} + BAN::Vector parts; - virtual bool is_scope() const override { return true; } + BAN::ErrorOr copy() const + { + Scope result; + TRY(result.parts.reserve(parts.size())); + for (uint32_t part : parts) + TRY(result.parts.push_back(part)); + return result; + } - static ParseResult parse(ParseContext& context); - - protected: - ParseResult enter_context_and_parse_term_list(ParseContext& outer_context, const AML::NameString& name, BAN::ConstByteSpan aml_data); + bool operator==(const Scope& other) const + { + if (parts.size() != other.parts.size()) + return false; + for (size_t i = 0; i < parts.size(); i++) + if (parts[i] != other.parts[i]) + return false; + return true; + } }; - bool initialize_scope(BAN::RefPtr scope); + BAN::ErrorOr initialize_scope(const Scope&); + +} + +namespace BAN +{ + + template<> + struct hash + { + hash_t operator()(const Kernel::ACPI::AML::Scope& scope) const + { + hash_t hash { 0 }; + for (uint32_t part : scope.parts) + hash ^= u32_hash(part); + return hash; + } + }; + +} + +namespace BAN::Formatter +{ + + template + void print_argument(F putc, const Kernel::ACPI::AML::Scope& scope, const ValueFormat&) + { + putc('\\'); + for (size_t i = 0; i < scope.parts.size(); i++) { + if (i != 0) + putc('.'); + const char* name_seg = reinterpret_cast(&scope.parts[i]); + putc(name_seg[0]); putc(name_seg[1]); putc(name_seg[2]); putc(name_seg[3]); + } + } } diff --git a/kernel/include/kernel/ACPI/AML/SizeOf.h b/kernel/include/kernel/ACPI/AML/SizeOf.h deleted file mode 100644 index 92396ec8..00000000 --- a/kernel/include/kernel/ACPI/AML/SizeOf.h +++ /dev/null @@ -1,60 +0,0 @@ -#pragma once - - -#include -#include -#include -#include -#include - -namespace Kernel::ACPI::AML -{ - - struct SizeOf - { - static ParseResult parse(ParseContext& context) - { - ASSERT(context.aml_data.size() >= 1); - ASSERT(static_cast(context.aml_data[0]) == Byte::SizeOfOp); - context.aml_data = context.aml_data.slice(1); - - auto object_result = AML::parse_object(context); - if (!object_result.success()) - return ParseResult::Failure; - auto object_node = object_result.node(); - if (object_node) - object_node = object_node->to_underlying(); - if (!object_node) - { - AML_ERROR("SizeOf object is null"); - return ParseResult::Failure; - } - if (object_node->type != AML::Node::Type::Package) - object_node = object_node->convert(AML::Node::ConvBuffer | AML::Node::ConvString); - if (!object_node) - { - AML_ERROR("SizeOf object is not Buffer, String or Package"); - return ParseResult::Failure; - } - - uint64_t size = 0; - switch (object_node->type) - { - case AML::Node::Type::Buffer: - size = static_cast(object_node.ptr())->buffer.size(); - break; - case AML::Node::Type::String: - size = static_cast(object_node.ptr())->string.size(); - break; - case AML::Node::Type::Package: - size = static_cast(object_node.ptr())->elements.size(); - break; - default: - ASSERT_NOT_REACHED(); - } - - return ParseResult(MUST(BAN::RefPtr::create(size))); - } - }; - -} diff --git a/kernel/include/kernel/ACPI/AML/Sleep.h b/kernel/include/kernel/ACPI/AML/Sleep.h deleted file mode 100644 index bcbf08e0..00000000 --- a/kernel/include/kernel/ACPI/AML/Sleep.h +++ /dev/null @@ -1,42 +0,0 @@ -#pragma once - -#include -#include -#include - -namespace Kernel::ACPI::AML -{ - - struct Sleep - { - static ParseResult parse(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::SleepOp); - context.aml_data = context.aml_data.slice(2); - - auto sleep_time_result = AML::parse_object(context); - if (!sleep_time_result.success()) - return ParseResult::Failure; - auto sleep_time_node = sleep_time_result.node() - ? sleep_time_result.node()->convert(AML::Node::ConvInteger) - : BAN::RefPtr(); - if (!sleep_time_node) - { - AML_ERROR("Sleep time cannot be evaluated to an integer"); - return ParseResult::Failure; - } - - const auto sleep_time_value = static_cast(sleep_time_node.ptr())->value; - -#if AML_DEBUG_LEVEL >= 2 - AML_DEBUG_PRINTLN("Sleeping for {} ms", sleep_time_value); -#endif - - SystemTimer::get().sleep_ms(sleep_time_value); - return ParseResult::Success; - } - }; - -} diff --git a/kernel/include/kernel/ACPI/AML/Store.h b/kernel/include/kernel/ACPI/AML/Store.h deleted file mode 100644 index c691f757..00000000 --- a/kernel/include/kernel/ACPI/AML/Store.h +++ /dev/null @@ -1,53 +0,0 @@ -#pragma once - -#include -#include - -namespace Kernel::ACPI::AML -{ - - struct Store - { - static ParseResult parse(ParseContext& context) - { - ASSERT(context.aml_data.size() >= 1); - ASSERT(static_cast(context.aml_data[0]) == Byte::StoreOp); - context.aml_data = context.aml_data.slice(1); - - auto source_result = AML::parse_object(context); - if (!source_result.success()) - return ParseResult::Failure; - auto source = source_result.node(); - if (!source) - { - AML_ERROR("Store source is null"); - return ParseResult::Failure; - } - - auto destination_result = AML::parse_object(context); - if (!destination_result.success()) - return ParseResult::Failure; - auto destination = destination_result.node(); - if (!destination) - { - AML_ERROR("Store destination is null"); - return ParseResult::Failure; - } - -#if AML_DEBUG_LEVEL >= 2 - AML_DEBUG_PRINTLN("Storing {"); - source->debug_print(1); - AML_DEBUG_PRINTLN(""); - AML_DEBUG_PRINTLN("} to {"); - destination->debug_print(1); - AML_DEBUG_PRINTLN(""); - AML_DEBUG_PRINTLN("}"); -#endif - - if (auto stored = destination->store(source)) - return ParseResult(stored); - return ParseResult::Failure; - } - }; - -} diff --git a/kernel/include/kernel/ACPI/AML/String.h b/kernel/include/kernel/ACPI/AML/String.h deleted file mode 100644 index e5a40dbf..00000000 --- a/kernel/include/kernel/ACPI/AML/String.h +++ /dev/null @@ -1,69 +0,0 @@ -#pragma once - -#include -#include -#include - -namespace Kernel::ACPI::AML -{ - - struct String final : public AML::Node - { - BAN::Vector string; - - String() : Node(Node::Type::String) {} - String(BAN::StringView string) - : Node(Node::Type::String) - { - MUST(this->string.resize(string.size())); - for (size_t i = 0; i < string.size(); i++) - this->string[i] = string[i]; - } - - BAN::Optional logical_compare(BAN::RefPtr node, AML::Byte binaryop); - - BAN::RefPtr convert(uint8_t mask) override; - - BAN::RefPtr copy() override - { - auto new_string = MUST(BAN::RefPtr::create()); - MUST(new_string->string.resize(this->string.size())); - for (size_t i = 0; i < this->string.size(); i++) - new_string->string[i] = this->string[i]; - return new_string; - } - - BAN::RefPtr store(BAN::RefPtr node) override - { - ASSERT(node); - auto conv_node = node->convert(AML::Node::ConvString); - if (!conv_node) - { - AML_ERROR("Could not convert to String"); - return {}; - } - auto* string_node = static_cast(conv_node.ptr()); - MUST(string.resize(string_node->string.size())); - for (size_t i = 0; i < string.size(); i++) - string[i] = string_node->string[i]; - return string_node->copy(); - } - - BAN::StringView string_view() const - { - return BAN::StringView(reinterpret_cast(string.data()), string.size()); - } - - static ParseResult parse(ParseContext& context); - - virtual void debug_print(int indent) const override - { - AML_DEBUG_PRINT_INDENT(indent); - AML_DEBUG_PRINT("String \"{}\"", string_view()); - } - - private: - BAN::RefPtr as_buffer(); - }; - -} diff --git a/kernel/include/kernel/ACPI/AML/ThermalZone.h b/kernel/include/kernel/ACPI/AML/ThermalZone.h deleted file mode 100644 index 3328042a..00000000 --- a/kernel/include/kernel/ACPI/AML/ThermalZone.h +++ /dev/null @@ -1,64 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include - -namespace Kernel::ACPI::AML -{ - - struct ThermalZone final : public AML::Scope - { - ThermalZone(NameSeg name) - : Scope(Node::Type::ThermalZone, name) - {} - - BAN::RefPtr convert(uint8_t) override { return {}; } - - static ParseResult parse(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::ThermalZoneOp); - context.aml_data = context.aml_data.slice(2); - - auto opt_thermal_zone_pkg = AML::parse_pkg(context.aml_data); - if (!opt_thermal_zone_pkg.has_value()) - return ParseResult::Failure; - auto thermal_zone_pkg = opt_thermal_zone_pkg.value(); - - auto name = NameString::parse(thermal_zone_pkg); - if (!name.has_value()) - return ParseResult::Failure; - - auto thermal_zone = MUST(BAN::RefPtr::create(name->path.back())); - if (!Namespace::root_namespace()->add_named_object(context, name.value(), thermal_zone)) - return ParseResult::Success; - -#if AML_DEBUG_LEVEL >= 2 - thermal_zone->debug_print(0); - AML_DEBUG_PRINTLN(""); -#endif - - return thermal_zone->enter_context_and_parse_term_list(context, name.value(), thermal_zone_pkg); - } - - virtual void debug_print(int indent) const override - { - AML_DEBUG_PRINT_INDENT(indent); - AML_DEBUG_PRINT("ThermalZone {} {", name); - Namespace::root_namespace()->for_each_child(scope, - [&](const auto&, const auto& child) - { - child->debug_print(indent + 1); - AML_DEBUG_PRINTLN(""); - } - ); - AML_DEBUG_PRINT_INDENT(indent); - AML_DEBUG_PRINT("}"); - } - }; - -} diff --git a/kernel/include/kernel/ACPI/AML/Utils.h b/kernel/include/kernel/ACPI/AML/Utils.h deleted file mode 100644 index 280efcbb..00000000 --- a/kernel/include/kernel/ACPI/AML/Utils.h +++ /dev/null @@ -1,36 +0,0 @@ -#pragma once - -#include -#include - -// AML_DEBUG_LEVEL: -// 0: No debug output -// 1: Dump AML after parsing -// 2: Dump AML while parsing -#define AML_DEBUG_LEVEL 0 - -#define AML_TODO(...) \ - do { \ - BAN::Formatter::print(Debug::putchar, "\e[33mTODO: "); \ - BAN::Formatter::print(Debug::putchar, __VA_ARGS__); \ - BAN::Formatter::println(Debug::putchar, "\e[m"); \ - } while (0) - -#define AML_ERROR(...) \ - do { \ - BAN::Formatter::print(Debug::putchar, "\e[31mERROR: "); \ - BAN::Formatter::print(Debug::putchar, __VA_ARGS__); \ - BAN::Formatter::println(Debug::putchar, "\e[m"); \ - } while (0) - -#define AML_PRINT(...) BAN::Formatter::println(Debug::putchar, __VA_ARGS__) - -#define AML_DEBUG_PRINT_INDENT(indent) \ - do { \ - for (int i = 0; i < (indent) * 2; i++) \ - AML_DEBUG_PUTC(' '); \ - } while (0) - -#define AML_DEBUG_PUTC(c) Debug::putchar(c) -#define AML_DEBUG_PRINT(...) BAN::Formatter::print(Debug::putchar, __VA_ARGS__) -#define AML_DEBUG_PRINTLN(...) BAN::Formatter::println(Debug::putchar, __VA_ARGS__) diff --git a/kernel/include/kernel/ACPI/AML/While.h b/kernel/include/kernel/ACPI/AML/While.h deleted file mode 100644 index 4a770b60..00000000 --- a/kernel/include/kernel/ACPI/AML/While.h +++ /dev/null @@ -1,77 +0,0 @@ -#pragma once - -#include -#include -#include - -namespace Kernel::ACPI::AML -{ - - struct While - { - static ParseResult parse(ParseContext& context) - { - ASSERT(context.aml_data.size() >= 1); - - AML::Byte opcode = static_cast(context.aml_data[0]); - context.aml_data = context.aml_data.slice(1); - - switch (opcode) - { - case AML::Byte::BreakOp: - return ParseResult(ParseResult::Result::Breaked); - case AML::Byte::ContinueOp: - return ParseResult(ParseResult::Result::Continued); - case AML::Byte::WhileOp: - break; - default: - ASSERT_NOT_REACHED(); - } - - auto while_pkg = AML::parse_pkg(context.aml_data); - if (!while_pkg.has_value()) - return ParseResult::Failure; - - auto outer_aml_data = context.aml_data; - - bool breaked = false; - while (!breaked) - { - context.aml_data = while_pkg.value(); - - auto predicate_result = AML::parse_object(context); - if (!predicate_result.success()) - return ParseResult::Failure; - auto predicate_node = predicate_result.node() - ? predicate_result.node()->convert(AML::Node::ConvInteger) - : BAN::RefPtr(); - if (!predicate_node) - { - AML_ERROR("While predicate is not an integer"); - return ParseResult::Failure; - } - - if (!static_cast(predicate_node.ptr())->value) - break; - - while (context.aml_data.size() > 0) - { - auto object_result = AML::parse_object(context); - if (object_result.returned()) - return ParseResult(ParseResult::Result::Returned, object_result.node()); - if (object_result.breaked()) - breaked = true; - if (object_result.breaked() || object_result.continued()) - break; - if (!object_result.success()) - return ParseResult::Failure; - } - } - - context.aml_data = outer_aml_data; - - return ParseResult::Success; - } - }; - -} diff --git a/kernel/include/kernel/ACPI/Headers.h b/kernel/include/kernel/ACPI/Headers.h index 5970297e..17ce12a1 100644 --- a/kernel/include/kernel/ACPI/Headers.h +++ b/kernel/include/kernel/ACPI/Headers.h @@ -1,5 +1,6 @@ #pragma once +#include #include namespace Kernel::ACPI @@ -22,8 +23,8 @@ namespace Kernel::ACPI PlatformCommunicationChannel = 0x0A, }; - BAN::Optional read(); - bool write(uint64_t value); + BAN::ErrorOr read(); + BAN::ErrorOr write(uint64_t value); AddressSpaceID address_space_id; uint8_t register_bit_width; diff --git a/kernel/kernel/ACPI/ACPI.cpp b/kernel/kernel/ACPI/ACPI.cpp index 469b8e89..ae681734 100644 --- a/kernel/kernel/ACPI/ACPI.cpp +++ b/kernel/kernel/ACPI/ACPI.cpp @@ -1,13 +1,7 @@ #include #include #include -#include -#include -#include -#include -#include -#include -#include +#include #include #include #include @@ -112,64 +106,62 @@ acpi_release_global_lock: ASSERT(!acpi_release_global_lock(s_global_lock)); } - static BAN::Optional get_access_type(uint8_t access_size) + static BAN::ErrorOr get_access_type(uint8_t access_size) { switch (access_size) { - case 0: return AML::FieldRules::AccessType::Any; - case 1: return AML::FieldRules::AccessType::Byte; - case 2: return AML::FieldRules::AccessType::Word; - case 3: return AML::FieldRules::AccessType::DWord; - case 4: return AML::FieldRules::AccessType::QWord; + case 0: return 0; + case 1: return 1; + case 2: return 2; + case 3: return 3; + case 4: return 4; default: dwarnln("Unknown access size {}", access_size); - return {}; + return BAN::Error::from_errno(EFAULT); } } - BAN::Optional GAS::read() + BAN::ErrorOr GAS::read() { - auto access_type = get_access_type(access_size); - if (!access_type.has_value()) - return {}; + AML::OpRegion opregion; + opregion.address_space = address_space_id; + opregion.offset = address; + opregion.length = 0xFFFFFFFF; - auto op_region = MUST(BAN::RefPtr::create(""_sv, address_space_id, (uint64_t)address, 0xFFFFFFFF)); + AML::Node field_unit; + field_unit.type = AML::Node::Type::FieldUnit; + field_unit.as.field_unit.type = AML::FieldUnit::Type::Field; + field_unit.as.field_unit.as.field.opregion = opregion; + field_unit.as.field_unit.length = register_bit_width; + field_unit.as.field_unit.offset = register_bit_offset; + field_unit.as.field_unit.flags = TRY(get_access_type(access_size)); - auto field_rules = AML::FieldRules { - .access_type = access_type.value(), - .lock_rule = AML::FieldRules::LockRule::NoLock, - .update_rule = AML::FieldRules::UpdateRule::Preserve, - .access_attrib = AML::FieldRules::AccessAttrib::Normal, - .access_length = 0 - }; - auto field_element = MUST(BAN::RefPtr::create(""_sv, register_bit_offset, register_bit_width, field_rules)); - field_element->op_region = op_region; - - auto result = field_element->convert(AML::Node::ConvInteger); - if (!result) - return {}; - return static_cast(result.ptr())->value; + auto result = TRY(AML::convert_from_field_unit(field_unit, AML::ConvInteger, sizeof(uint64_t))); + return result.as.integer.value; } - bool GAS::write(uint64_t value) + BAN::ErrorOr GAS::write(uint64_t value) { - auto access_type = get_access_type(access_size); - if (!access_type.has_value()) - return {}; + AML::OpRegion opregion; + opregion.address_space = address_space_id; + opregion.offset = address; + opregion.length = 0xFFFFFFFF; - auto op_region = MUST(BAN::RefPtr::create(""_sv, address_space_id, (uint64_t)address, 0xFFFFFFFF)); + AML::Node field_unit; + field_unit.type = AML::Node::Type::FieldUnit; + field_unit.as.field_unit.type = AML::FieldUnit::Type::Field; + field_unit.as.field_unit.as.field.opregion = opregion; + field_unit.as.field_unit.length = register_bit_width; + field_unit.as.field_unit.offset = register_bit_offset; + field_unit.as.field_unit.flags = TRY(get_access_type(access_size)); - auto field_rules = AML::FieldRules { - .access_type = access_type.value(), - .lock_rule = AML::FieldRules::LockRule::NoLock, - .update_rule = AML::FieldRules::UpdateRule::Preserve, - .access_attrib = AML::FieldRules::AccessAttrib::Normal, - .access_length = 0 - }; - auto field_element = MUST(BAN::RefPtr::create(""_sv, register_bit_offset, register_bit_width, field_rules)); - field_element->op_region = op_region; + AML::Node source; + source.type = AML::Node::Type::Integer; + source.as.integer.value = value; - return !!field_element->store(MUST(BAN::RefPtr::create(value))); + TRY(AML::store_to_field_unit(source, field_unit)); + + return {}; } enum PM1Event : uint16_t @@ -474,77 +466,81 @@ acpi_release_global_lock: return nullptr; } - bool ACPI::prepare_sleep(uint8_t sleep_state) + BAN::ErrorOr ACPI::prepare_sleep(uint8_t sleep_state) { - auto pts_object = m_namespace->find_object({}, AML::NameString("_PTS"), AML::Namespace::FindMode::ForceAbsolute); - if (pts_object && pts_object->type == AML::Node::Type::Method) + auto [pts_path, pts_object] = TRY(m_namespace->find_named_object({}, MUST(AML::NameString::from_string("\\_PTS")))); + if (pts_object == nullptr) + return {}; + + auto& pts_node = pts_object->node; + if (pts_node.type != AML::Node::Type::Method) { - auto* method = static_cast(pts_object.ptr()); - if (method->arg_count != 1) - { - dwarnln("Method \\_PTS has {} arguments, expected 1", method->arg_count); - return false; - } - - if (!method->invoke(MUST(BAN::RefPtr::create(sleep_state))).has_value()) - { - dwarnln("Failed to evaluate \\_PTS"); - return false; - } - - dprintln("Executed \\_PTS"); + dwarnln("Object \\_PTS is not a method"); + return BAN::Error::from_errno(EFAULT); } - return true; + if (pts_node.as.method.arg_count != 1) + { + dwarnln("Method \\_PTS has {} arguments, expected 1", pts_node.as.method.arg_count); + return BAN::Error::from_errno(EFAULT); + } + + AML::Reference arg_ref; + arg_ref.node.type = AML::Node::Type::Integer; + arg_ref.node.as.integer.value = sleep_state; + arg_ref.ref_count = 2; + + BAN::Array arguments(nullptr); + arguments[0] = &arg_ref; // method call should not delete argument + TRY(AML::method_call(pts_path, pts_node, BAN::move(arguments))); + + dprintln("Executed \\_PTS({})", sleep_state); + + return {}; } - void ACPI::poweroff() + BAN::ErrorOr ACPI::poweroff() { if (!m_namespace) { dwarnln("ACPI namespace not initialized"); - return; + return BAN::Error::from_errno(EFAULT); } - auto s5_object = m_namespace->find_object({}, AML::NameString("_S5"), AML::Namespace::FindMode::ForceAbsolute); + auto [_, s5_object] = TRY(m_namespace->find_named_object({}, TRY(AML::NameString::from_string("\\_S5_"_sv)))); if (!s5_object) { dwarnln("\\_S5 not found"); - return; + return BAN::Error::from_errno(EFAULT); } - auto s5_evaluated = s5_object->to_underlying(); - if (!s5_evaluated) - { - dwarnln("Failed to evaluate \\_S5"); - return; - } - if (s5_evaluated->type != AML::Node::Type::Package) + + auto& s5_node = s5_object->node; + if (s5_node.type != AML::Node::Type::Package) { dwarnln("\\_S5 is not a package"); - return; + return BAN::Error::from_errno(EFAULT); } - auto* s5_package = static_cast(s5_evaluated.ptr()); - if (s5_package->elements.size() < 2) + if (s5_node.as.package->num_elements < 2) { - dwarnln("\\_S5 package has {} elements, expected atleast 2", s5_package->elements.size()); - return; + dwarnln("\\_S5 package has {} elements, expected atleast 2", s5_node.as.package->num_elements); + return BAN::Error::from_errno(EFAULT); } - 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) + if (!s5_node.as.package->elements[0].resolved || !s5_node.as.package->elements[1].resolved) { - dwarnln("Failed to get SLP_TYPx values"); - return; + dwarnln("TODO: lazy evaluate package \\_S5 elements"); + return BAN::Error::from_errno(ENOTSUP); } - if (!prepare_sleep(5)) - return; + auto slp_typa_node = TRY(AML::convert_node(TRY(s5_node.as.package->elements[0].value.node->copy()), AML::ConvInteger, sizeof(uint64_t))); + auto slp_typb_node = TRY(AML::convert_node(TRY(s5_node.as.package->elements[1].value.node->copy()), AML::ConvInteger, sizeof(uint64_t))); + + TRY(prepare_sleep(5)); dprintln("Entering sleep state S5"); - const auto slp_typa_value = static_cast(slp_typa_node.ptr())->value; - const auto slp_typb_value = static_cast(slp_typb_node.ptr())->value; + const auto slp_typa_value = slp_typa_node.as.integer.value; + const auto slp_typb_value = slp_typb_node.as.integer.value; uint16_t pm1a_data = IO::inw(fadt().pm1a_cnt_blk); pm1a_data &= ~(PM1_CNT_SLP_TYP_MASK << PM1_CNT_SLP_TYP_SHIFT); @@ -562,11 +558,10 @@ acpi_release_global_lock: } // system must not execute after sleep registers are written - g_paniced = true; - asm volatile("ud2"); + ASSERT_NOT_REACHED(); } - void ACPI::reset() + BAN::ErrorOr ACPI::reset() { // https://uefi.org/htmlspecs/ACPI_Spec_6_4_html/04_ACPI_Hardware_Specification/ACPI_Hardware_Specification.html#reset-register @@ -579,36 +574,64 @@ acpi_release_global_lock: break; default: dwarnln("Reset register has invalid address space ID ({})", static_cast(reset_reg.address_space_id)); - return; + return BAN::Error::from_errno(EFAULT); } + if (reset_reg.register_bit_offset != 0 || reset_reg.register_bit_width != 8) { dwarnln("Reset register has invalid location ({} bits at bit offset {})", reset_reg.register_bit_width, reset_reg.register_bit_offset); - return; + return BAN::Error::from_errno(EFAULT); } - if (!prepare_sleep(5)) - return; + TRY(prepare_sleep(5)); dprintln("Resetting system"); - if (!reset_reg.write(fadt().reset_value)) - { - dwarnln("Could not write reset value"); - return; - } + TRY(reset_reg.write(fadt().reset_value)); // system must not execute after reset register is written - g_paniced = true; - asm volatile("ud2"); + ASSERT_NOT_REACHED(); + } + + BAN::ErrorOr ACPI::load_aml_tables(BAN::StringView name, bool all) + { + BAN::ErrorOr result {}; + + for (uint32_t i = 0;; i++) + { + auto* header = get_header(name, i); + if (header == nullptr) + break; + + if (all) + dprintln("Parsing {}{}, {} bytes", name, i + 1, header->length); + else + dprintln("Parsing {}, {} bytes", name, header->length); + + auto header_span = BAN::ConstByteSpan(reinterpret_cast(header), header->length); + if (auto parse_ret = m_namespace->parse(header_span); parse_ret.is_error()) + result = parse_ret.release_error(); + + if (!all) + break; + } + + return result; } BAN::ErrorOr ACPI::enter_acpi_mode(uint8_t mode) { ASSERT(!m_namespace); - m_namespace = AML::initialize_namespace(); - if (!m_namespace) - return BAN::Error::from_errno(EFAULT); + + TRY(AML::Namespace::initialize_root_namespace()); + m_namespace = &AML::Namespace::root_namespace(); + + if (auto ret = load_aml_tables("DSDT"_sv, false); ret.is_error()) + dwarnln("Could not load DSDT: {}", ret.error()); + if (auto ret = load_aml_tables("SSDT"_sv, true); ret.is_error()) + dwarnln("Could not load all SSDTs: {}", ret.error()); + if (auto ret = load_aml_tables("PSDT"_sv, true); ret.is_error()) + dwarnln("Could not load all PSDTs: {}", ret.error()); // https://uefi.org/htmlspecs/ACPI_Spec_6_4_html/16_Waking_and_Sleeping/initialization.html#placing-the-system-in-acpi-mode @@ -639,30 +662,43 @@ acpi_release_global_lock: dprintln("Entered ACPI mode"); - dprintln("Initializing devices"); + dprintln("Calling opregion _REG methods"); + + if (auto ret = m_namespace->initalize_op_regions(); ret.is_error()) + dwarnln("failed to call _REG methods: {}", ret.error()); + + dprintln("Initializing \\_SB"); // Initialize \\_SB - auto _sb = m_namespace->find_object({}, AML::NameString("_SB"), AML::Namespace::FindMode::ForceAbsolute); - if (_sb && _sb->is_scope()) - { - auto* scope = static_cast(_sb.ptr()); - AML::initialize_scope(scope); - } + auto [sb_path, sb_obj] = TRY(m_namespace->find_named_object({}, TRY(AML::NameString::from_string("\\_SB_"_sv)))); + if (sb_obj && sb_obj->node.is_scope()) + if (auto ret = AML::initialize_scope(sb_path); ret.is_error()) + dwarnln("Failed to initialize \\_SB: {}", ret.error()); + + dprintln("Evaluating \\_PIC"); // Evaluate \\_PIC (mode) - auto _pic = m_namespace->find_object({}, AML::NameString("_PIC"), AML::Namespace::FindMode::ForceAbsolute); - if (_pic && _pic->type == AML::Node::Type::Method) + auto [pic_path, pic_obj] = TRY(m_namespace->find_named_object({}, TRY(AML::NameString::from_string("\\_PIC"_sv)))); + if (pic_obj && pic_obj->node.type == AML::Node::Type::Method) { - auto* method = static_cast(_pic.ptr()); - if (method->arg_count != 1) + auto& pic_node = pic_obj->node; + if (pic_node.as.method.arg_count != 1) { - dwarnln("Method \\_PIC has {} arguments, expected 1", method->arg_count); + dwarnln("Method \\_PIC has {} arguments, expected 1", pic_node.as.method.arg_count); return BAN::Error::from_errno(EINVAL); } - method->invoke(MUST(BAN::RefPtr::create(mode))); + + AML::Reference arg_ref; + arg_ref.node.type = AML::Node::Type::Integer; + arg_ref.node.as.integer.value = mode; + arg_ref.ref_count = 2; + + BAN::Array arguments(nullptr); + arguments[0] = &arg_ref; // method call should not delete argument + TRY(AML::method_call(pic_path, pic_node, BAN::move(arguments))); } - dprintln("Devices are initialized"); + dprintln("Initializing ACPI interrupts"); uint8_t irq = fadt().sci_int; if (auto ret = InterruptController::get().reserve_irq(irq); ret.is_error()) @@ -690,34 +726,43 @@ acpi_release_global_lock: if (fadt().gpe0_blk) { - // Enable all events in _GPE (_Lxx or _Exx) - m_namespace->for_each_child(AML::NameString("\\_GPE"), - [&](const auto& path, auto& node) - { - if (node->type != AML::Node::Type::Method) - return; - if (path.size() < 4) - return; + auto [gpe_scope, gpe_obj] = TRY(m_namespace->find_named_object({}, TRY(AML::NameString::from_string("\\_GPE")))); + if (gpe_obj && gpe_obj->node.is_scope()) + { + m_gpe_scope = BAN::move(gpe_scope); - auto name = path.sv().substring(path.size() - 4); - if (name.substring(0, 2) != "_L"_sv && name.substring(0, 2) != "_E"_sv) - return; + // Enable all events in _GPE (_Lxx or _Exx) + TRY(m_namespace->for_each_child(m_gpe_scope, + [&](BAN::StringView name, AML::Reference* node_ref) -> BAN::Iteration + { + if (node_ref->node.type != AML::Node::Type::Method) + return BAN::Iteration::Continue; - auto index = hex_sv_to_int(name.substring(2)); - if (!index.has_value()) - return; + ASSERT(name.size() == 4); + if (!name.starts_with("_L"_sv) && !name.starts_with("_E"_sv)) + return BAN::Iteration::Continue; - auto byte = index.value() / 8; - auto bit = index.value() % 8; - auto gpe0_en_port = fadt().gpe0_blk + (fadt().gpe0_blk_len / 2) + byte; - IO::outb(gpe0_en_port, IO::inb(gpe0_en_port) | (1 << bit)); + auto index = hex_sv_to_int(name.substring(2)); + if (!index.has_value()) + { + dwarnln("invalid GPE number '{}'", name); + return BAN::Iteration::Continue; + } - auto* method = static_cast(node.ptr()); - m_gpe_methods[index.value()] = method; + auto byte = index.value() / 8; + auto bit = index.value() % 8; + auto gpe0_en_port = fadt().gpe0_blk + (fadt().gpe0_blk_len / 2) + byte; + IO::outb(gpe0_en_port, IO::inb(gpe0_en_port) | (1 << bit)); - dprintln("Enabled GPE {}", index.value(), byte, bit); - } - ); + m_gpe_methods[index.value()] = node_ref; + node_ref->ref_count++; + + dprintln("Enabled GPE {}", index.value(), byte, bit); + + return BAN::Iteration::Continue; + } + )); + } } set_irq(irq); @@ -769,7 +814,8 @@ acpi_release_global_lock: auto index = i * 8 + (pending & ~(pending - 1)); if (m_gpe_methods[index]) - m_gpe_methods[index]->invoke(); + if (auto ret = AML::method_call(m_gpe_scope, m_gpe_methods[index]->node, {}); ret.is_error()) + dwarnln("Failed to evaluate _GPE {}: ", index, ret.error()); handled_event = true; IO::outb(fadt().gpe0_blk + i, 1 << index); diff --git a/kernel/kernel/ACPI/AML.cpp b/kernel/kernel/ACPI/AML.cpp deleted file mode 100644 index 9aa1adbd..00000000 --- a/kernel/kernel/ACPI/AML.cpp +++ /dev/null @@ -1,60 +0,0 @@ -#include -#include -#include -#include - -namespace Kernel::ACPI -{ - - static void load_all(AML::Namespace& ns, BAN::StringView signature) - { - for (uint32_t i = 0;; i++) - { - auto* header = ACPI::ACPI::get().get_header(signature, i); - if (!header) - break; - - dprintln("Parsing {}{} ({} bytes)", signature, i, header->length); - if (!ns.parse(*header)) - { - dwarnln("Failed to parse {}", signature); - continue; - } - } - } - - BAN::RefPtr AML::initialize_namespace() - { - auto ns = AML::Namespace::create_root_namespace(); - - // https://uefi.org/htmlspecs/ACPI_Spec_6_4_html/05_ACPI_Software_Programming_Model/ACPI_Software_Programming_Model.html#differentiated-system-description-table-dsdt - auto* dsdt = ACPI::ACPI::get().get_header("DSDT", 0); - if (!dsdt) - { - dwarnln("Failed to get DSDT"); - return {}; - } - dprintln("Parsing DSDT ({} bytes)", dsdt->length); - if (!ns->parse(*dsdt)) - { - dwarnln("Failed to parse DSDT"); - return {}; - } - - // https://uefi.org/htmlspecs/ACPI_Spec_6_4_html/05_ACPI_Software_Programming_Model/ACPI_Software_Programming_Model.html#secondary-system-description-table-ssdt - load_all(*ns, "SSDT"); - - // https://uefi.org/htmlspecs/ACPI_Spec_6_4_html/05_ACPI_Software_Programming_Model/ACPI_Software_Programming_Model.html#persistent-system-description-table-psdt - load_all(*ns, "PSDT"); - -#if AML_DEBUG_LEVEL >= 1 - ns->debug_print(0); - AML_DEBUG_PRINTLN(""); -#endif - - dprintln("Parsed ACPI namespace, total of {} nodes created", AML::Node::total_node_count); - - return ns; - } - -} diff --git a/kernel/kernel/ACPI/AML/Field.cpp b/kernel/kernel/ACPI/AML/Field.cpp deleted file mode 100644 index d2b2d66a..00000000 --- a/kernel/kernel/ACPI/AML/Field.cpp +++ /dev/null @@ -1,881 +0,0 @@ -#include -#include -#include -#include -#include -#include - -namespace Kernel::ACPI -{ - - template - concept ReadFunc = requires(Func func, uint64_t offset) - { - requires BAN::is_same_v>; - }; - - template - concept WriteFunc = requires(Func func, uint64_t offset, uint64_t value) - { - requires BAN::is_same_v; - }; - - template - struct ParseFieldElementContext - { - AML::FieldRules field_rules; - uint64_t field_bit_offset; - BAN::ConstByteSpan field_pkg; - BAN::HashMap> elements; - }; - - template - static bool parse_field_element(ParseFieldElementContext& context) - { - // FIXME: Validate elements - - ASSERT(context.field_pkg.size() >= 1); - switch (context.field_pkg[0]) - { - case 0x00: - { - context.field_pkg = context.field_pkg.slice(1); - - auto reserved_length = AML::parse_pkg_length(context.field_pkg); - if (!reserved_length.has_value()) - { - AML_ERROR("Invalid FieldElement length for reserved field"); - return false; - } - AML::trim_pkg_length(context.field_pkg); - - context.field_bit_offset += reserved_length.value(); - return true; - } - case 0x01: - { - context.field_pkg = context.field_pkg.slice(1); - - if (context.field_pkg.size() < 2) - { - AML_ERROR("Invalid FieldElement length for access field"); - return false; - } - - context.field_rules.access_type = static_cast(context.field_pkg[0] & 0x0F); - context.field_rules.access_attrib = static_cast((context.field_pkg[0] >> 6) & 0x03); - context.field_pkg = context.field_pkg.slice(1); - - context.field_rules.access_length = context.field_pkg[0]; - context.field_pkg = context.field_pkg.slice(1); - - return true; - } - case 0x02: - AML_TODO("Field element Connection", context.field_pkg[0]); - return false; - case 0x03: - { - context.field_pkg = context.field_pkg.slice(1); - - if (context.field_pkg.size() < 3) - { - AML_ERROR("Invalid FieldElement length for extended access field"); - return false; - } - - context.field_rules.access_type = static_cast(context.field_pkg[0] & 0x0F); - context.field_rules.lock_rule = static_cast((context.field_pkg[0] >> 4) & 0x01); - context.field_rules.update_rule = static_cast((context.field_pkg[0] >> 5) & 0x03); - context.field_pkg = context.field_pkg.slice(1); - - if (context.field_pkg[0] == 0x0B) - context.field_rules.access_attrib = AML::FieldRules::AccessAttrib::Bytes; - else if (context.field_pkg[0] == 0x0E) - context.field_rules.access_attrib = AML::FieldRules::AccessAttrib::RawBytes; - else if (context.field_pkg[0] == 0x0F) - context.field_rules.access_attrib = AML::FieldRules::AccessAttrib::RawProcessBytes; - else - { - AML_ERROR("Invalid FieldElement extended access field attribute"); - return false; - } - context.field_pkg = context.field_pkg.slice(1); - - context.field_rules.access_length = context.field_pkg[0]; - context.field_pkg = context.field_pkg.slice(1); - - return true; - } - default: - { - auto element_name = AML::NameSeg::parse(context.field_pkg); - if (!element_name.has_value()) - { - AML_ERROR("Invalid FieldElement name for named field"); - return false; - } - - auto element_length = AML::parse_pkg_length(context.field_pkg); - if (!element_length.has_value()) - { - AML_ERROR("Invalid FieldElement length for named field"); - return false; - } - AML::trim_pkg_length(context.field_pkg); - - if (context.elements.contains(element_name.value())) - { - AML_ERROR("Field element already exists"); - return false; - } - - MUST(context.elements.emplace( - element_name.value(), - MUST(BAN::RefPtr::create( - element_name.value(), - context.field_bit_offset, - element_length.value(), - context.field_rules - )) - )); - context.field_bit_offset += element_length.value(); - - return true; - } - } - } - - static BAN::Optional determine_access_size(const AML::FieldRules::AccessType& access_type) - { - switch (access_type) - { - case AML::FieldRules::AccessType::Any: - case AML::FieldRules::AccessType::Byte: - return 1; - case AML::FieldRules::AccessType::Word: - return 2; - case AML::FieldRules::AccessType::DWord: - return 4; - case AML::FieldRules::AccessType::QWord: - return 8; - case AML::FieldRules::AccessType::Buffer: - AML_TODO("FieldElement with access type Buffer"); - return {}; - } - return {}; - } - - static BAN::Optional perform_read(AML::OpRegion::RegionSpace region_space, uint64_t access_offset, uint32_t access_size) - { - switch (region_space) - { - case AML::OpRegion::RegionSpace::SystemMemory: - { - uint64_t result = 0; - size_t index_in_page = (access_offset % PAGE_SIZE) / access_size; - PageTable::with_fast_page(access_offset & PAGE_ADDR_MASK, [&] { - switch (access_size) - { - case 1: result = PageTable::fast_page_as_sized (index_in_page); break; - case 2: result = PageTable::fast_page_as_sized(index_in_page); break; - case 4: result = PageTable::fast_page_as_sized(index_in_page); break; - case 8: result = PageTable::fast_page_as_sized(index_in_page); break; - } - }); - return result; - } - case AML::OpRegion::RegionSpace::SystemIO: - { - uint64_t result = 0; - switch (access_size) - { - case 1: result = IO::inb(access_offset); break; - case 2: result = IO::inw(access_offset); break; - case 4: result = IO::inl(access_offset); break; - default: - AML_ERROR("FieldElement read_field (SystemIO) with access size {}", access_size); - return {}; - } - return result; - } - case AML::OpRegion::RegionSpace::PCIConfig: - { - // https://uefi.org/htmlspecs/ACPI_Spec_6_4_html/05_ACPI_Software_Programming_Model/ACPI_Software_Programming_Model.html#address-space-format - // PCI configuration space is confined to segment 0, bus 0 - - uint16_t device = (access_offset >> 32) & 0xFFFF; - uint16_t function = (access_offset >> 16) & 0xFFFF; - uint16_t offset = access_offset & 0xFFFF; - - uint64_t result = 0; - switch (access_size) - { - case 1: result = PCI::PCIManager::get().read_config_byte(0, device, function, offset); break; - case 2: result = PCI::PCIManager::get().read_config_word(0, device, function, offset); break; - case 4: result = PCI::PCIManager::get().read_config_dword(0, device, function, offset); break; - default: - AML_ERROR("FieldElement read_field (PCIConfig) with access size {}", access_size); - return {}; - } - return result; - } - default: - AML_TODO("FieldElement read_field with region space {}", static_cast(region_space)); - return {}; - } - } - - static bool perform_write(AML::OpRegion::RegionSpace region_space, uint64_t access_offset, uint32_t access_size, uint64_t value) - { - switch (region_space) - { - case AML::OpRegion::RegionSpace::SystemMemory: - { - size_t index_in_page = (access_offset % PAGE_SIZE) / access_size; - PageTable::with_fast_page(access_offset & PAGE_ADDR_MASK, [&] { - switch (access_size) - { - case 1: PageTable::fast_page_as_sized (index_in_page) = value; break; - case 2: PageTable::fast_page_as_sized(index_in_page) = value; break; - case 4: PageTable::fast_page_as_sized(index_in_page) = value; break; - case 8: PageTable::fast_page_as_sized(index_in_page) = value; break; - } - }); - return true; - } - case AML::OpRegion::RegionSpace::SystemIO: - { - switch (access_size) - { - case 1: IO::outb(access_offset, value); break; - case 2: IO::outw(access_offset, value); break; - case 4: IO::outl(access_offset, value); break; - default: - AML_ERROR("FieldElement write_field (SystemIO) with access size {}", access_size); - return false; - } - return true; - } - case AML::OpRegion::RegionSpace::PCIConfig: - { - // https://uefi.org/htmlspecs/ACPI_Spec_6_4_html/05_ACPI_Software_Programming_Model/ACPI_Software_Programming_Model.html#address-space-format - // PCI configuration space is confined to segment 0, bus 0 - - uint16_t device = (access_offset >> 32) & 0xFFFF; - uint16_t function = (access_offset >> 16) & 0xFFFF; - uint16_t offset = access_offset & 0xFFFF; - - switch (access_size) - { - case 1: PCI::PCIManager::get().write_config_byte(0, device, function, offset, value); break; - case 2: PCI::PCIManager::get().write_config_word(0, device, function, offset, value); break; - case 4: PCI::PCIManager::get().write_config_dword(0, device, function, offset, value); break; - default: - AML_ERROR("FieldElement write_field (PCIConfig) with access size {}", access_size); - return false; - } - return true; - } - default: - AML_TODO("FieldElement write_field with region space {}", static_cast(region_space)); - return false; - } - } - - template - static BAN::Optional perform_read_general( - uint64_t base_byte_offset, - uint64_t bit_count, - uint64_t bit_offset, - uint32_t access_size, - ReadFunc& read_func - ) - { - if (bit_count > 64) - { - AML_TODO("Field read with bit_count > 64"); - return {}; - } - - uint32_t access_bytes = access_size; - uint32_t access_bits = access_bytes * 8; - - uint64_t result = 0; - uint32_t bits_read = 0; - while (bits_read < bit_count) - { - uint64_t byte_offset = base_byte_offset + ((bit_offset + bits_read) / 8); - if (auto rem = byte_offset % access_bytes) - byte_offset -= rem; - - auto partial = read_func(byte_offset); - if (!partial.has_value()) - return {}; - - uint32_t shift = (bit_offset + bits_read) % access_bits; - uint32_t valid_bits = BAN::Math::min(access_bits - shift, bit_count - bits_read); - uint64_t mask = ((uint64_t)1 << valid_bits) - 1; - - result |= ((partial.value() >> shift) & mask) << bits_read; - bits_read += valid_bits; - } - - return result; - } - - template - static bool perform_write_general( - uint64_t base_byte_offset, - uint64_t bit_count, - uint64_t bit_offset, - uint32_t access_size, - uint64_t value, - AML::FieldRules::UpdateRule update_rule, - ReadFunc& read_func, - WriteFunc& write_func - ) - { - if (bit_count > 64) - { - AML_TODO("Field write with bit_count > 64"); - return false; - } - - uint32_t access_bytes = access_size; - uint32_t access_bits = access_bytes * 8; - - uint32_t bits_written = 0; - while (bits_written < bit_count) - { - uint64_t byte_offset = base_byte_offset + ((bit_offset + bits_written) / 8); - if (auto rem = byte_offset % access_bytes) - byte_offset -= rem; - - uint32_t shift = (bit_offset + bits_written) % access_bits; - uint32_t valid_bits = BAN::Math::min(access_bits - shift, bit_count - bits_written); - uint64_t mask = ((uint64_t)1 << valid_bits) - 1; - - uint64_t to_write = 0; - if (valid_bits != access_bits) - { - switch (update_rule) - { - case AML::FieldRules::UpdateRule::Preserve: - { - auto read_result = read_func(byte_offset); - if (!read_result.has_value()) - return false; - to_write = read_result.value() & ~(mask << shift); - break; - } - case AML::FieldRules::UpdateRule::WriteAsOnes: - to_write = ~(mask << shift); - break; - case AML::FieldRules::UpdateRule::WriteAsZeros: - to_write = 0; - break; - } - } - to_write |= ((value >> bits_written) & mask) << shift; - - if (!write_func(byte_offset, to_write)) - return false; - - bits_written += valid_bits; - } - - return true; - } - - AML::ParseResult AML::Field::parse(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::FieldOp); - context.aml_data = context.aml_data.slice(2); - - auto opt_field_pkg = AML::parse_pkg(context.aml_data); - if (!opt_field_pkg.has_value()) - return ParseResult::Failure; - auto field_pkg = opt_field_pkg.release_value(); - - auto name_string = NameString::parse(field_pkg); - if (!name_string.has_value()) - return ParseResult::Failure; - - auto op_region = Namespace::root_namespace()->find_object(context.scope, name_string.value(), Namespace::FindMode::Normal); - if (!op_region || op_region->type != AML::Node::Type::OpRegion) - { - AML_ERROR("FieldOp: {} does not name a valid OpRegion", name_string.value()); - return ParseResult::Failure; - } - - if (field_pkg.size() < 1) - return ParseResult::Failure; - auto field_flags = field_pkg[0]; - field_pkg = field_pkg.slice(1); - - ParseFieldElementContext field_context; - field_context.field_rules.access_type = static_cast(field_flags & 0x0F); - field_context.field_rules.lock_rule = static_cast((field_flags >> 4) & 0x01); - field_context.field_rules.update_rule = static_cast((field_flags >> 5) & 0x03); - field_context.field_bit_offset = 0; - field_context.field_pkg = field_pkg; - while (field_context.field_pkg.size() > 0) - if (!parse_field_element(field_context)) - return ParseResult::Failure; - - for (auto& [_, element] : field_context.elements) - { - element->op_region = static_cast(op_region.ptr()); - - NameString element_name; - MUST(element_name.path.push_back(element->name)); - if (!Namespace::root_namespace()->add_named_object(context, element_name, element)) - return ParseResult::Failure; - -#if AML_DEBUG_LEVEL >= 2 - element->debug_print(0); - AML_DEBUG_PRINTLN(""); -#endif - } - - return ParseResult::Success; - } - - BAN::Optional AML::FieldElement::evaluate_internal() - { - if (access_rules.access_attrib != FieldRules::AccessAttrib::Normal) - { - AML_TODO("FieldElement 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()); - }; - return perform_read_general(op_region->region_offset, bit_count, bit_offset, access_size.value(), read_func); - } - - bool AML::FieldElement::store_internal(uint64_t value) - { - if (access_rules.access_attrib != FieldRules::AccessAttrib::Normal) - { - AML_TODO("FieldElement 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 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); - }; - 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::FieldElement::as_integer() - { - op_region->mutex.lock(); - BAN::ScopeGuard unlock_guard([&] { - op_region->mutex.unlock(); - }); - - auto result = evaluate_internal(); - if (!result.has_value()) - return {}; - return MUST(BAN::RefPtr::create(result.value())); - } - - BAN::RefPtr AML::FieldElement::store(BAN::RefPtr source) - { - ASSERT(source); - auto source_integer = source->convert(AML::Node::ConvInteger); - if (!source_integer) - { - AML_TODO("FieldElement store with non-integer source, type {}", static_cast(source->type)); - return {}; - } - - op_region->mutex.lock(); - if (access_rules.lock_rule == FieldRules::LockRule::Lock) - ACPI::acquire_global_lock(); - BAN::ScopeGuard unlock_guard([&] { - op_region->mutex.unlock(); - if (access_rules.lock_rule == FieldRules::LockRule::Lock) - ACPI::release_global_lock(); - }); - - if (!store_internal(static_cast(source_integer.ptr())->value)) - return {}; - return source_integer; - } - - void AML::FieldElement::debug_print(int indent) const - { - AML_DEBUG_PRINT_INDENT(indent); - AML_DEBUG_PRINT("FieldElement {} ({}, offset {}, OpRegion {})", - name, - bit_count, - bit_offset, - op_region->name - ); - } - - AML::ParseResult AML::IndexField::parse(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::IndexFieldOp); - context.aml_data = context.aml_data.slice(2); - - auto opt_field_pkg = AML::parse_pkg(context.aml_data); - if (!opt_field_pkg.has_value()) - return ParseResult::Failure; - auto field_pkg = opt_field_pkg.release_value(); - - auto index_field_element_name = NameString::parse(field_pkg); - if (!index_field_element_name.has_value()) - return ParseResult::Failure; - auto index_field_element = Namespace::root_namespace()->find_object(context.scope, index_field_element_name.value(), Namespace::FindMode::Normal); - if (!index_field_element || index_field_element->type != AML::Node::Type::FieldElement) - { - AML_ERROR("IndexField IndexName does not name a valid FieldElement"); - return ParseResult::Failure; - } - - auto data_field_element_name = NameString::parse(field_pkg); - if (!data_field_element_name.has_value()) - return ParseResult::Failure; - auto data_field_element = Namespace::root_namespace()->find_object(context.scope, data_field_element_name.value(), Namespace::FindMode::Normal); - if (!data_field_element || data_field_element->type != AML::Node::Type::FieldElement) - { - AML_ERROR("IndexField DataName does not name a valid FieldElement"); - return ParseResult::Failure; - } - - if (field_pkg.size() < 1) - return ParseResult::Failure; - auto field_flags = field_pkg[0]; - field_pkg = field_pkg.slice(1); - - ParseFieldElementContext field_context; - field_context.field_rules.access_type = static_cast(field_flags & 0x0F); - field_context.field_rules.lock_rule = static_cast((field_flags >> 4) & 0x01); - field_context.field_rules.update_rule = static_cast((field_flags >> 5) & 0x03); - field_context.field_bit_offset = 0; - field_context.field_pkg = field_pkg; - while (field_context.field_pkg.size() > 0) - if (!parse_field_element(field_context)) - return ParseResult::Failure; - - for (auto& [_, element] : field_context.elements) - { - element->index_element = static_cast(index_field_element.ptr()); - element->data_element = static_cast(data_field_element.ptr()); - - NameString element_name; - MUST(element_name.path.push_back(element->name)); - if (!Namespace::root_namespace()->add_named_object(context, element_name, element)) - return ParseResult::Failure; - -#if AML_DEBUG_LEVEL >= 2 - element->debug_print(0); - AML_DEBUG_PRINTLN(""); -#endif - } - - return AML::ParseResult::Success; - } - - BAN::RefPtr AML::IndexFieldElement::as_integer() - { - if (access_rules.access_attrib != FieldRules::AccessAttrib::Normal) - { - AML_TODO("IndexFieldElement 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 {}; - if (access_size.value() > data_element->bit_count) - { - AML_ERROR("IndexFieldElement read_field with access size {} > data element bit count {}", access_size.value(), data_element->bit_count); - return {}; - } - auto read_func = [&](uint64_t byte_offset) -> BAN::Optional { - if (!index_element->store_internal(byte_offset)) - return {}; - return data_element->evaluate_internal(); - }; - - index_element->op_region->mutex.lock(); - if (access_rules.lock_rule == FieldRules::LockRule::Lock) - ACPI::acquire_global_lock(); - BAN::ScopeGuard unlock_guard([&] { - index_element->op_region->mutex.unlock(); - if (access_rules.lock_rule == FieldRules::LockRule::Lock) - ACPI::release_global_lock(); - }); - - auto result = perform_read_general(0, bit_count, bit_offset, access_size.value(), read_func); - if (!result.has_value()) - return {}; - return MUST(BAN::RefPtr::create(result.value())); - } - - BAN::RefPtr AML::IndexFieldElement::store(BAN::RefPtr source) - { - if (access_rules.access_attrib != FieldRules::AccessAttrib::Normal) - { - AML_TODO("FieldElement with access attribute {}", static_cast(access_rules.access_attrib)); - return {}; - } - - ASSERT(source); - auto source_integer = source->convert(AML::Node::ConvInteger); - if (!source_integer) - { - AML_TODO("IndexFieldElement store with non-integer source, type {}", static_cast(source->type)); - return {}; - } - - auto access_size = determine_access_size(access_rules.access_type); - if (!access_size.has_value()) - 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 {}; - } - - auto read_func = [&](uint64_t byte_offset) -> BAN::Optional { - if (!index_element->store_internal(byte_offset)) - return {}; - return data_element->evaluate_internal(); - }; - auto write_func = [&](uint64_t byte_offset, uint64_t value) -> bool { - if (!index_element->store_internal(byte_offset)) - return {}; - return data_element->store_internal(value); - }; - - index_element->op_region->mutex.lock(); - if (access_rules.lock_rule == FieldRules::LockRule::Lock) - ACPI::acquire_global_lock(); - BAN::ScopeGuard unlock_guard([&] { - index_element->op_region->mutex.unlock(); - if (access_rules.lock_rule == FieldRules::LockRule::Lock) - ACPI::release_global_lock(); - }); - - const auto source_value = static_cast(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 - { - AML_DEBUG_PRINT_INDENT(indent); - AML_DEBUG_PRINT("IndexFieldElement {} ({}, offset {}, IndexName {}, DataName {})", - name, - bit_count, - bit_offset, - index_element->name, - data_element->name - ); - } - - AML::ParseResult AML::BankField::parse(ParseContext& context) - { - // BankFieldOp PkgLength NameString NameString BankValue FieldFlags FieldList - - 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::BankFieldOp); - context.aml_data = context.aml_data.slice(2); - - auto opt_field_pkg = AML::parse_pkg(context.aml_data); - if (!opt_field_pkg.has_value()) - return ParseResult::Failure; - auto field_pkg = opt_field_pkg.release_value(); - - auto op_region_name = NameString::parse(field_pkg); - if (!op_region_name.has_value()) - return ParseResult::Failure; - auto op_region = Namespace::root_namespace()->find_object(context.scope, op_region_name.value(), Namespace::FindMode::Normal); - if (!op_region || op_region->type != AML::Node::Type::OpRegion) - { - AML_ERROR("BankField RegionName {} does not name a valid OpRegion", op_region_name.value()); - return ParseResult::Failure; - } - - auto bank_selector_name = NameString::parse(field_pkg); - if (!bank_selector_name.has_value()) - return ParseResult::Failure; - auto bank_selector = Namespace::root_namespace()->find_object(context.scope, bank_selector_name.value(), Namespace::FindMode::Normal); - if (!bank_selector) - { - 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; - auto bank_value_result = AML::parse_object(context); - field_pkg = context.aml_data; - context.aml_data = temp_aml_data; - if (!bank_value_result.success()) - return ParseResult::Failure; - auto bank_value_node = bank_value_result.node() ? bank_value_result.node()->convert(AML::Node::ConvInteger) : BAN::RefPtr(); - if (!bank_value_node) - { - AML_ERROR("BankField BankValue is not an integer"); - return ParseResult::Failure; - } - - if (field_pkg.size() < 1) - return ParseResult::Failure; - auto field_flags = field_pkg[0]; - field_pkg = field_pkg.slice(1); - - ParseFieldElementContext field_context; - field_context.field_rules.access_type = static_cast(field_flags & 0x0F); - field_context.field_rules.lock_rule = static_cast((field_flags >> 4) & 0x01); - field_context.field_rules.update_rule = static_cast((field_flags >> 5) & 0x03); - field_context.field_bit_offset = 0; - field_context.field_pkg = field_pkg; - while (field_context.field_pkg.size() > 0) - if (!parse_field_element(field_context)) - return ParseResult::Failure; - - const auto bank_value = static_cast(bank_value_node.ptr())->value; - for (auto& [_, element] : field_context.elements) - { - element->op_region = static_cast(op_region.ptr()); - element->bank_selector = static_cast(bank_selector.ptr()); - element->bank_value = bank_value; - - NameString element_name; - MUST(element_name.path.push_back(element->name)); - if (!Namespace::root_namespace()->add_named_object(context, element_name, element)) - return ParseResult::Failure; - -#if AML_DEBUG_LEVEL >= 2 - element->debug_print(0); - AML_DEBUG_PRINTLN(""); -#endif - } - - return ParseResult::Success; - } - - BAN::RefPtr AML::BankFieldElement::as_integer() - { - 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())); - } - - BAN::RefPtr 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 {}; - } - - ASSERT(source); - auto source_integer = source->convert(AML::Node::ConvInteger); - if (!source_integer) - { - AML_TODO("BankFieldElement store with non-integer source, type {}", static_cast(source->type)); - 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()); - }; - 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 {}; - } - - const auto source_value = static_cast(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 - { - AML_DEBUG_PRINT_INDENT(indent); - AML_DEBUG_PRINT("BankFieldElement {} ({}, offset {}, OpRegion {}, BankSelector {}, BankValue {H})", - name, - bit_count, - bit_offset, - op_region->name, - bank_selector->name, - bank_value - ); - } - -} diff --git a/kernel/kernel/ACPI/AML/Integer.cpp b/kernel/kernel/ACPI/AML/Integer.cpp deleted file mode 100644 index 75a38967..00000000 --- a/kernel/kernel/ACPI/AML/Integer.cpp +++ /dev/null @@ -1,183 +0,0 @@ -#include -#include -#include - -namespace Kernel::ACPI -{ - - AML::Integer::Integer(uint64_t value, bool constant) - : Node(Node::Type::Integer) - , value(value) - , constant(constant) - {} - - BAN::Optional AML::Integer::logical_compare(BAN::RefPtr node, AML::Byte binaryop) - { - auto rhs_node = node ? node->convert(AML::Node::ConvInteger) : BAN::RefPtr(); - if (!rhs_node) - { - AML_ERROR("Integer logical compare RHS cannot be converted to"); - return {}; - } - const auto rhs_value = static_cast(rhs_node.ptr())->value; - - switch (binaryop) - { - case AML::Byte::LAndOp: return value && rhs_value; - case AML::Byte::LEqualOp: return value == rhs_value; - case AML::Byte::LGreaterOp: return value > rhs_value; - case AML::Byte::LLessOp: return value < rhs_value; - case AML::Byte::LOrOp: return value || rhs_value; - default: - ASSERT_NOT_REACHED(); - } - } - - BAN::RefPtr AML::Integer::convert(uint8_t mask) - { - if (mask & AML::Node::ConvInteger) - return this; - if (mask & AML::Node::ConvBuffer) - { - auto buffer = MUST(BAN::RefPtr::create()); - MUST(buffer->buffer.resize(8)); - for (size_t i = 0; i < 8; i++) - buffer->buffer[i] = (value >> (56 - i * 8)) & 0xFF; - return buffer; - } - if (mask & AML::Node::ConvBufferField) - { - AML_TODO("Convert Integer to BufferField"); - return {}; - } - if (mask & AML::Node::ConvFieldUnit) - { - AML_TODO("Convert Integer to FieldUnit"); - return {}; - } - if (mask & AML::Node::ConvString) - { - constexpr auto get_hex_char = - [](uint8_t nibble) - { - return (nibble < 10 ? '0' : 'A' - 10) + nibble; - }; - - auto string = MUST(BAN::RefPtr::create()); - MUST(string->string.resize(16)); - for (size_t i = 0; i < 16; i++) - string->string[i] = get_hex_char((value >> (60 - i * 4)) & 0xF); - return string; - } - return {}; - } - - BAN::RefPtr AML::Integer::copy() - { - return MUST(BAN::RefPtr::create(value)); - } - - BAN::RefPtr AML::Integer::store(BAN::RefPtr store_node) - { - if (constant) - { - AML_ERROR("Cannot store to constant integer"); - return {}; - } - auto conv_node = store_node ? store_node->convert(AML::Node::ConvInteger) : BAN::RefPtr(); - if (!conv_node) - { - AML_ERROR("Cannot store non-integer to integer"); - return {}; - } - value = static_cast(conv_node.ptr())->value; - return MUST(BAN::RefPtr::create(value)); - } - - AML::ParseResult AML::Integer::parse(BAN::ConstByteSpan& aml_data) - { - switch (static_cast(aml_data[0])) - { - case AML::Byte::ZeroOp: - aml_data = aml_data.slice(1); - // FIXME: no copy - return ParseResult(Constants::Zero->copy()); - case AML::Byte::OneOp: - aml_data = aml_data.slice(1); - // FIXME: no copy - return ParseResult(Constants::One->copy()); - case AML::Byte::OnesOp: - aml_data = aml_data.slice(1); - // FIXME: no copy - return ParseResult(Constants::Ones->copy()); - case AML::Byte::BytePrefix: - { - if (aml_data.size() < 2) - return ParseResult::Failure; - const uint8_t value = aml_data[1]; - aml_data = aml_data.slice(2); - return ParseResult(MUST(BAN::RefPtr::create(value))); - } - case AML::Byte::WordPrefix: - { - if (aml_data.size() < 3) - return ParseResult::Failure; - uint16_t value = 0; - value |= aml_data[1] << 0; - value |= aml_data[2] << 8; - aml_data = aml_data.slice(3); - return ParseResult(MUST(BAN::RefPtr::create(value))); - } - case AML::Byte::DWordPrefix: - { - if (aml_data.size() < 5) - return ParseResult::Failure; - uint32_t value = 0; - value |= static_cast(aml_data[1]) << 0; - value |= static_cast(aml_data[2]) << 8; - value |= static_cast(aml_data[3]) << 16; - value |= static_cast(aml_data[4]) << 24; - aml_data = aml_data.slice(5); - return ParseResult(MUST(BAN::RefPtr::create(value))); - } - case AML::Byte::QWordPrefix: - { - if (aml_data.size() < 9) - return ParseResult::Failure; - uint64_t value = 0; - value |= static_cast(aml_data[1]) << 0; - value |= static_cast(aml_data[2]) << 8; - value |= static_cast(aml_data[3]) << 16; - value |= static_cast(aml_data[4]) << 24; - value |= static_cast(aml_data[5]) << 32; - value |= static_cast(aml_data[6]) << 40; - value |= static_cast(aml_data[7]) << 48; - value |= static_cast(aml_data[8]) << 56; - aml_data = aml_data.slice(9); - return ParseResult(MUST(BAN::RefPtr::create(value))); - } - default: - ASSERT_NOT_REACHED(); - } - } - - void AML::Integer::debug_print(int indent) const - { - AML_DEBUG_PRINT_INDENT(indent); - if (!constant) - AML_DEBUG_PRINT("0x{H}", value); - else - { - AML_DEBUG_PRINT("Const "); - if (value == Constants::Zero->value) - AML_DEBUG_PRINT("Zero"); - else if (value == Constants::One->value) - AML_DEBUG_PRINT("One"); - else if (value == Constants::Ones->value) - AML_DEBUG_PRINT("Ones"); - else - ASSERT_NOT_REACHED(); - } - } - -} diff --git a/kernel/kernel/ACPI/AML/NamedObject.cpp b/kernel/kernel/ACPI/AML/NamedObject.cpp deleted file mode 100644 index ff132d1d..00000000 --- a/kernel/kernel/ACPI/AML/NamedObject.cpp +++ /dev/null @@ -1,46 +0,0 @@ -#include -#include -#include -#include -#include - -namespace Kernel::ACPI -{ - - AML::ParseResult AML::Name::parse(ParseContext& context) - { - ASSERT(context.aml_data.size() >= 1); - ASSERT(static_cast(context.aml_data[0]) == Byte::NameOp); - context.aml_data = context.aml_data.slice(1); - - auto name_string = AML::NameString::parse(context.aml_data); - if (!name_string.has_value()) - return ParseResult::Failure; - - auto object = AML::parse_object(context); - if (!object.success()) - return ParseResult::Failure; - - auto name = MUST(BAN::RefPtr::create(name_string.value().path.back(), object.node())); - if (!Namespace::root_namespace()->add_named_object(context, name_string.value(), name)) - return ParseResult::Success; - -#if AML_DEBUG_LEVEL >= 2 - name->debug_print(0); - AML_DEBUG_PRINTLN(""); -#endif - - return ParseResult::Success; - } - - void AML::Name::debug_print(int indent) const - { - AML_DEBUG_PRINT_INDENT(indent); - AML_DEBUG_PRINTLN("Name {} { ", name); - object->debug_print(indent + 1); - AML_DEBUG_PRINTLN(""); - AML_DEBUG_PRINT_INDENT(indent); - AML_DEBUG_PRINT("}"); - } - -} diff --git a/kernel/kernel/ACPI/AML/Namespace.cpp b/kernel/kernel/ACPI/AML/Namespace.cpp index c6d0e313..c33ed8bf 100644 --- a/kernel/kernel/ACPI/AML/Namespace.cpp +++ b/kernel/kernel/ACPI/AML/Namespace.cpp @@ -1,311 +1,438 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include -namespace Kernel::ACPI +#include +#include +#include + +namespace Kernel::ACPI::AML { - static BAN::RefPtr s_root_namespace; - static BAN::Vector s_osi_aml_data; + static Namespace s_root_namespace; - BAN::RefPtr AML::Integer::Constants::Zero; - BAN::RefPtr AML::Integer::Constants::One; - BAN::RefPtr AML::Integer::Constants::Ones; - - struct DebugNode : AML::Node - { - DebugNode() : AML::Node(AML::Node::Type::Debug) {} - BAN::RefPtr convert(uint8_t) override { return {}; } - BAN::RefPtr store(BAN::RefPtr node) - { - node->debug_print(0); - AML_DEBUG_PRINTLN(""); - return node; - } - void debug_print(int indent) const override - { - AML_DEBUG_PRINT_INDENT(indent); - AML_DEBUG_PRINT("DEBUG"); - } + static constexpr BAN::StringView s_supported_osi_strings[] { + "Windows 2000"_sv, + "Windows 2001"_sv, + "Windows 2001 SP1"_sv, + "Windows 2001.1"_sv, + "Windows 2001 SP2"_sv, + "Windows 2001.1 SP1"_sv, + "Windows 2006.1"_sv, + "Windows 2006 SP1"_sv, + "Windows 2006 SP2"_sv, + "Windows 2009"_sv, + "Windows 2012"_sv, + "Windows 2013"_sv, + "Windows 2015"_sv, + "Windows 2016"_sv, + "Windows 2017"_sv, + "Windows 2017.2"_sv, + "Windows 2018"_sv, + "Windows 2018.2"_sv, + "Windows 2019"_sv, + "Extended Address Space Descriptor"_sv, + // just to pass osi test from uACPI :D + "AnotherTestString"_sv, }; - BAN::RefPtr AML::Namespace::debug_node; - - BAN::RefPtr AML::Namespace::root_namespace() + Namespace::~Namespace() { - ASSERT(s_root_namespace); - return s_root_namespace; + for (auto& [_, reference] : m_named_objects) + if (--reference->ref_count == 0) + delete reference; } - void AML::Namespace::debug_print(int indent) const + BAN::ErrorOr Namespace::initialize_root_namespace() { - LockGuard _(m_object_mutex); - AML_DEBUG_PRINT_INDENT(indent); - AML_DEBUG_PRINTLN("Namespace {} {", name); - for_each_child(scope, [&](const auto&, const auto& child) { - child->debug_print(indent + 1); - AML_DEBUG_PRINTLN(""); - }); - AML_DEBUG_PRINT_INDENT(indent); - AML_DEBUG_PRINT("}"); - } + // https://uefi.org/htmlspecs/ACPI_Spec_6_4_html/05_ACPI_Software_Programming_Model/ACPI_Software_Programming_Model.html?highlight=predefined#predefined-root-namespaces - BAN::Optional AML::Namespace::resolve_path(const AML::NameString& relative_base, const AML::NameString& relative_path, FindMode mode, bool check_existence) const - { - LockGuard _(m_object_mutex); - - // Base must be non-empty absolute path - ASSERT(relative_base.prefix == "\\"_sv || relative_base.path.empty()); - - // Do absolute path lookup - if (!relative_path.prefix.empty() || relative_path.path.size() != 1 || mode == FindMode::ForceAbsolute) - { - BAN::String absolute_path; - MUST(absolute_path.push_back('\\')); - - // Resolve root and parent references - if (relative_path.prefix == "\\"_sv) - ; - else + const auto add_predefined_root_namespace = + [](const char* name) -> BAN::ErrorOr { - if (relative_path.prefix.size() > relative_base.path.size()) - { - AML_ERROR("Trying to resolve parent of root object"); - return {}; - } - for (size_t i = 0; i < relative_base.path.size() - relative_path.prefix.size(); i++) - { - MUST(absolute_path.append(relative_base.path[i].sv())); - MUST(absolute_path.push_back('.')); - } - } + Node predefined {}; + predefined.type = Node::Type::PredefinedScope; + TRY(s_root_namespace.add_named_object({}, TRY(NameString::from_string(name)), BAN::move(predefined))); + return {}; + }; - // Append relative path - for (const auto& seg : relative_path.path) - { - MUST(absolute_path.append(seg.sv())); - MUST(absolute_path.push_back('.')); - } + TRY(add_predefined_root_namespace("\\")); + TRY(add_predefined_root_namespace("\\_GPE")); + TRY(add_predefined_root_namespace("\\_PR_")); + TRY(add_predefined_root_namespace("\\_SB_")); + TRY(add_predefined_root_namespace("\\_SI_")); + TRY(add_predefined_root_namespace("\\_TZ_")); - if (absolute_path.back() == '.') - absolute_path.pop_back(); - - if (!check_existence || absolute_path == "\\"_sv || m_objects.contains(absolute_path)) - return absolute_path; - return {}; - } - - - // Resolve with namespace search rules (ACPI Spec 6.4 - Section 5.3) - - AML::NameSeg target_seg = relative_path.path.back(); - - BAN::String last_match_path; - BAN::String current_path; - MUST(current_path.push_back('\\')); - - // Check root namespace { - BAN::String tmp; - MUST(tmp.append(current_path)); - MUST(tmp.append(target_seg.sv())); - if (m_objects.contains(tmp)) - last_match_path = BAN::move(tmp); + Node revision; + revision.type = Node::Type::Integer; + revision.as.integer.value = 2; + TRY(s_root_namespace.add_named_object({}, TRY(NameString::from_string("_REV")), BAN::move(revision))); } - // Check base base path - for (const auto& seg : relative_base.path) { - MUST(current_path.append(seg.sv())); - MUST(current_path.push_back('.')); + auto osi_string = TRY(NameString::from_string("\\_OSI")); - BAN::String tmp; - MUST(tmp.append(current_path)); - MUST(tmp.append(target_seg.sv())); - if (m_objects.contains(tmp)) - last_match_path = BAN::move(tmp); + Node method {}; + method.type = Node::Type::Method; + new (method.as.method.storage) Kernel::Mutex(); + method.as.method.arg_count = 1; + method.as.method.override_func = + [](const BAN::Array& args) -> BAN::ErrorOr + { + ASSERT(args[0]); + + if (args[0]->node.type != Node::Type::String) + { + dwarnln("_OSI called with {}", args[0]->node); + return BAN::Error::from_errno(EINVAL); + } + + const auto arg0 = BAN::StringView( + reinterpret_cast(args[0]->node.as.str_buf->bytes), + args[0]->node.as.str_buf->size + ); + + Node result {}; + result.type = Node::Type::Integer; + result.as.integer.value = 0; + + for (auto supported : s_supported_osi_strings) + { + if (supported != arg0) + continue; + result.as.integer.value = 0xFFFFFFFFFFFFFFFF; + break; + } + + return result; + }; + + TRY(s_root_namespace.add_named_object({}, osi_string, BAN::move(method))); + } + + { + auto gl_string = TRY(NameString::from_string("\\_GL_")); + + Node mutex {}; + mutex.type = Node::Type::Mutex; + mutex.as.mutex = new Mutex(); + mutex.as.mutex->ref_count = 1; + mutex.as.mutex->sync_level = 0; + mutex.as.mutex->global_lock = true; + + TRY(s_root_namespace.add_named_object({}, gl_string, BAN::move(mutex))); } - if (!last_match_path.empty()) - return last_match_path; return {}; } - BAN::RefPtr AML::Namespace::find_object(const AML::NameString& relative_base, const AML::NameString& relative_path, FindMode mode) + Namespace& Namespace::root_namespace() { - LockGuard _(m_object_mutex); - - auto canonical_path = resolve_path(relative_base, relative_path, mode); - if (!canonical_path.has_value()) - return nullptr; - - if (canonical_path->sv() == "\\"_sv) - return this; - - auto it = m_objects.find(canonical_path.value()); - if (it == m_objects.end()) - return {}; - return it->value; - } - - bool AML::Namespace::add_named_object(ParseContext& parse_context, const AML::NameString& object_path, BAN::RefPtr object) - { - LockGuard _(m_object_mutex); - - ASSERT(!object_path.path.empty()); - - auto canonical_path = resolve_path(parse_context.scope, object_path, FindMode::ForceAbsolute, false); - ASSERT(canonical_path.has_value()); - ASSERT(!canonical_path->empty()); - - if (m_objects.contains(canonical_path.value())) - { - AML_PRINT("Object '{}' already exists", canonical_path.value()); - return false; - } - - auto canonical_scope = AML::NameString(canonical_path.value()); - - MUST(m_objects.insert(canonical_path.value(), object)); - if (object->is_scope()) - { - auto* scope = static_cast(object.ptr()); - scope->scope = canonical_scope; - } - - MUST(parse_context.created_objects.push_back(canonical_scope)); - - return true; - } - - bool AML::Namespace::remove_named_object(const AML::NameString& absolute_path) - { - LockGuard _(m_object_mutex); - - auto canonical_path = resolve_path({}, absolute_path, FindMode::ForceAbsolute); - if (!canonical_path.has_value()) - { - AML_ERROR("Trying to delete non-existent object '{}'", absolute_path); - return false; - } - - if (canonical_path->empty()) - { - AML_ERROR("Trying to remove root namespace"); - return false; - } - - ASSERT(m_objects.contains(canonical_path.value())); - m_objects.remove(canonical_path.value()); - - return true; - } - - BAN::RefPtr AML::Namespace::create_root_namespace() - { - ASSERT(!s_root_namespace); - s_root_namespace = MUST(BAN::RefPtr::create(NameSeg("\\"_sv))); - s_root_namespace->scope = AML::NameString("\\"_sv); - - ASSERT(!Namespace::debug_node); - Namespace::debug_node = MUST(BAN::RefPtr::create()); - - Integer::Constants::Zero = MUST(BAN::RefPtr::create(0, true)); - Integer::Constants::One = MUST(BAN::RefPtr::create(1, true)); - Integer::Constants::Ones = MUST(BAN::RefPtr::create(0xFFFFFFFFFFFFFFFF, true)); - - AML::ParseContext context; - context.scope = AML::NameString("\\"_sv); - - // Add predefined namespaces -#define ADD_PREDEFIED_NAMESPACE(NAME) \ - ASSERT(s_root_namespace->add_named_object(context, AML::NameString("\\" NAME), MUST(BAN::RefPtr::create(NameSeg(NAME))))); - ADD_PREDEFIED_NAMESPACE("_GPE"_sv); - ADD_PREDEFIED_NAMESPACE("_PR"_sv); - ADD_PREDEFIED_NAMESPACE("_SB"_sv); - ADD_PREDEFIED_NAMESPACE("_SI"_sv); - ADD_PREDEFIED_NAMESPACE("_TZ"_sv); -#undef ADD_PREDEFIED_NAMESPACE - - auto gl = MUST(BAN::RefPtr::create(NameSeg("_GL"_sv), 0, true)); - ASSERT(s_root_namespace->add_named_object(context, AML::NameString("\\_GL"), gl)); - - // Add \_OSI that returns true for Linux compatibility - auto osi = MUST(BAN::RefPtr::create(NameSeg("_OSI"_sv), 1, false, 0)); - osi->override_function = [](AML::ParseContext& context) -> BAN::RefPtr { - ASSERT(context.method_args[0]); - auto arg = context.method_args[0]->convert(AML::Node::ConvString); - if (!arg || arg->type != AML::Node::Type::String) - { - AML_ERROR("Invalid _OSI argument"); - return {}; - } - - constexpr BAN::StringView valid_strings[] { - "Windows 2000"_sv, - "Windows 2001"_sv, - "Windows 2001 SP1"_sv, - "Windows 2001.1"_sv, - "Windows 2001 SP2"_sv, - "Windows 2001.1 SP1"_sv, - "Windows 2006.1"_sv, - "Windows 2006 SP1"_sv, - "Windows 2006 SP2"_sv, - "Windows 2009"_sv, - "Windows 2012"_sv, - "Windows 2013"_sv, - "Windows 2015"_sv, - "Windows 2016"_sv, - "Windows 2017"_sv, - "Windows 2017.2"_sv, - "Windows 2018"_sv, - "Windows 2018.2"_sv, - "Windows 2019"_sv, - "Extended Address Space Descriptor"_sv, - // just to pass osi test from uACPI :D - "AnotherTestString"_sv, - }; - - auto string = static_cast(arg.ptr())->string_view(); - for (auto valid_string : valid_strings) - if (string == valid_string) - return AML::Integer::Constants::Ones; - return AML::Integer::Constants::Zero; - }; - ASSERT(s_root_namespace->add_named_object(context, AML::NameString("\\_OSI"), osi)); - - auto os_string = MUST(BAN::RefPtr::create("banan-os"_sv)); - auto os = MUST(BAN::RefPtr::create("_OS"_sv, os_string)); - ASSERT(s_root_namespace->add_named_object(context, AML::NameString("\\_OS"), os)); - return s_root_namespace; } - bool AML::Namespace::parse(const SDTHeader& header) + BAN::ErrorOr Namespace::initalize_op_regions() { - ASSERT(this == s_root_namespace.ptr()); + m_has_parsed_namespace = true; - AML::ParseContext context; - context.scope = AML::NameString("\\"_sv); - context.aml_data = BAN::ConstByteSpan(reinterpret_cast(&header), header.length).slice(sizeof(header)); - - while (context.aml_data.size() > 0) + for (const auto& [obj_path, obj_ref] : m_named_objects) { - auto result = AML::parse_object(context); - if (!result.success()) + if (obj_ref->node.type != Node::Type::OpRegion) + continue; + // FIXME: if _REG adds stuff to namespace, iterators are invalidated + (void)opregion_call_reg(obj_path, obj_ref->node); + } + + return {}; + } + + BAN::ErrorOr Namespace::opregion_call_reg(const Scope& scope, const Node& opregion) + { + ASSERT(opregion.type == Node::Type::OpRegion); + + const auto address_space = opregion.as.opregion.address_space; + if (address_space == GAS::AddressSpaceID::SystemIO || address_space == GAS::AddressSpaceID::SystemMemory) + return {}; + const uint32_t address_space_u32 = static_cast(address_space); + if (address_space_u32 >= 32) + return {}; + const uint32_t mask = static_cast(1) << address_space_u32; + + auto parent = TRY(scope.copy()); + parent.parts.pop_back(); + + auto it = m_called_reg_bitmaps.find(parent); + if (it != m_called_reg_bitmaps.end()) + if (it->value & mask) + return {}; + + auto [reg_path, reg_obj] = TRY(find_named_object(parent, TRY(NameString::from_string("_REG"_sv)), true)); + if (reg_obj != nullptr) + { + if (reg_obj->node.type != Node::Type::Method) + dwarnln("{} is not an method", reg_path); + else { - AML_ERROR("Failed to parse object"); - return false; + if (reg_obj->node.as.method.arg_count != 2) + dwarnln("{} takes {} arguments", reg_obj->node.as.method.arg_count); + else + { + Reference arg0; + arg0.node.type = Node::Type::Integer; + arg0.node.as.integer.value = address_space_u32; + arg0.ref_count = 2; // evaluate should not delete + + Reference arg1; + arg1.node.type = Node::Type::Integer; + arg1.node.as.integer.value = 1; + arg1.ref_count = 2; // evaluate should not delete + + BAN::Array args(nullptr); + args[0] = &arg0; + args[1] = &arg1; + + if (auto ret = method_call(reg_path, reg_obj->node, BAN::move(args)); ret.is_error()) + dwarnln("Failed to evaluate {}: {}", reg_path, ret.error()); + } } } - return true; + if (it != m_called_reg_bitmaps.end()) + it->value |= mask; + else + TRY(m_called_reg_bitmaps.insert(BAN::move(parent), mask)); + + return {}; + } + + BAN::ErrorOr Namespace::resolve_path(const Scope& scope, const NameString& name_string) + { + Scope resolved_path; + + if (name_string.base == NameString::base_root) + { + TRY(resolved_path.parts.reserve(name_string.parts.size())); + for (uint32_t part : name_string.parts) + TRY(resolved_path.parts.push_back(part)); + } + else + { + const uint32_t scope_segment_count = + (name_string.base < scope.parts.size()) + ? scope.parts.size() - name_string.base + : 0; + + TRY(resolved_path.parts.reserve(scope_segment_count + name_string.parts.size())); + for (size_t i = 0; i < scope_segment_count; i++) + TRY(resolved_path.parts.push_back(scope.parts[i])); + for (uint32_t part : name_string.parts) + TRY(resolved_path.parts.push_back(part)); + } + + return resolved_path; + } + + BAN::ErrorOr Namespace::add_named_object(const Scope& scope, const NameString& name_string, Node&& node) + { + dprintln_if(AML_DUMP_FUNCTION_CALLS, "add_named_object('{}', '{}', {})", scope, name_string, node); + + auto resolved_path = TRY(resolve_path(scope, name_string)); + if (m_named_objects.contains(resolved_path)) + return Scope(); + + auto* reference = new Reference(); + if (reference == nullptr) + return BAN::Error::from_errno(ENOMEM); + reference->node = BAN::move(node); + reference->ref_count = 1; + + TRY(m_named_objects.insert(TRY(resolved_path.copy()), reference)); + + if (m_has_parsed_namespace && reference->node.type == Node::Type::OpRegion) + (void)opregion_call_reg(resolved_path, reference->node); + + return resolved_path; + } + + BAN::ErrorOr Namespace::add_named_object(const Scope& scope, const NameString& name_string, Reference* reference) + { + dprintln_if(AML_DUMP_FUNCTION_CALLS, "add_named_object('{}', '{}', {})", scope, name_string, reference->node); + + auto resolved_path = TRY(resolve_path(scope, name_string)); + if (m_named_objects.contains(resolved_path)) + return Scope(); + + ASSERT(reference->ref_count >= 1); + reference->ref_count++; + + TRY(m_named_objects.insert(TRY(resolved_path.copy()), reference)); + return resolved_path; + } + + BAN::ErrorOr Namespace::remove_named_object(const Scope& absolute_path) + { + dprintln_if(AML_DUMP_FUNCTION_CALLS, "remove_named_object('{}')", absolute_path); + + auto it = m_named_objects.find(absolute_path); + if (it == m_named_objects.end()) + return BAN::Error::from_errno(ENOENT); + if (--it->value->ref_count == 0) + delete it->value; + m_named_objects.remove(it); + return {}; + } + + BAN::ErrorOr Namespace::find_named_object(const Scope& scope, const NameString& name_string, bool force_absolute) + { + dprintln_if(AML_DUMP_FUNCTION_CALLS, "find_named_object('{}', '{}')", scope, name_string); + + if (force_absolute || name_string.base != 0) + { + // Absolute path + + auto resolved_path = TRY(resolve_path(scope, name_string)); + auto it = m_named_objects.find(resolved_path); + if (it != m_named_objects.end()) { + return FindResult { + .path = BAN::move(resolved_path), + .node = it->value, + }; + } + + return FindResult { + .path = {}, + .node = nullptr, + }; + } + + // Relative path + + Scope path_guess; + TRY(path_guess.parts.reserve(scope.parts.size() + name_string.parts.size())); + for (const auto& part : scope.parts) + TRY(path_guess.parts.push_back(part)); + for (const auto& part : name_string.parts) + TRY(path_guess.parts.push_back(part)); + + auto it = m_named_objects.find(path_guess); + if (it != m_named_objects.end()) { + return FindResult { + .path = BAN::move(path_guess), + .node = it->value, + }; + } + + for (size_t i = 0; i < scope.parts.size(); i++) + { + path_guess.parts.remove(scope.parts.size() - i - 1); + auto it = m_named_objects.find(path_guess); + if (it != m_named_objects.end()) { + return FindResult { + .path = BAN::move(path_guess), + .node = it->value, + }; + } + } + + return FindResult { + .path = {}, + .node = nullptr, + }; + } + + BAN::ErrorOr Namespace::for_each_child(const Scope& scope, const BAN::Function& callback) + { + for (const auto& [obj_path, obj_ref] : m_named_objects) + { + if (obj_path.parts.size() != scope.parts.size() + 1) + continue; + + bool match = true; + for (size_t i = 0; i < scope.parts.size() && match; i++) + match = obj_path.parts[i] == scope.parts[i]; + if (!match) + continue; + + auto name = BAN::StringView(reinterpret_cast(&obj_path.parts.back()), 4); + auto iteration = callback(name, obj_ref); + if (iteration == BAN::Iteration::Break) + break; + ASSERT(iteration == BAN::Iteration::Continue); + } + + return {}; + } + + BAN::ErrorOr Namespace::for_each_child(const Scope& scope, const BAN::Function& callback) + { + for (const auto& [obj_path, obj_ref] : m_named_objects) + { + if (obj_path.parts.size() != scope.parts.size() + 1) + continue; + + bool match = true; + for (size_t i = 0; i < scope.parts.size() && match; i++) + match = obj_path.parts[i] == scope.parts[i]; + if (!match) + continue; + + auto iteration = callback(obj_path, obj_ref); + if (iteration == BAN::Iteration::Break) + break; + ASSERT(iteration == BAN::Iteration::Continue); + } + + return {}; + } + + BAN::ErrorOr Namespace::evaluate(BAN::StringView path) + { + Scope root_scope; + auto name_string = TRY(NameString::from_string(path)); + auto [object_path, object] = TRY(find_named_object(root_scope, name_string)); + if (object == nullptr) + return BAN::Error::from_errno(ENOENT); + return evaluate_node(object_path, object->node); + } + + BAN::ErrorOr Namespace::parse(BAN::ConstByteSpan aml_data) + { + if (aml_data.size() < sizeof(SDTHeader)) + return BAN::Error::from_errno(EINVAL); + + const auto& sdt_header = aml_data.as(); + if (aml_data.size() < sdt_header.length) + return BAN::Error::from_errno(EINVAL); + + aml_data = aml_data.slice(sizeof(SDTHeader)); + + ParseContext context; + context.aml_data = aml_data; + TRY(context.allocate_locals()); + + while (!context.aml_data.empty()) + { + auto parse_result = parse_node_or_execution_flow(context); + if (parse_result.is_error()) + { + dwarnln("Failed to parse root namespace: {}", parse_result.error()); + return parse_result.release_error(); + } + + auto [execution_flow, node] = parse_result.release_value(); + if (execution_flow == ExecutionFlow::Normal) + continue; + if (execution_flow == ExecutionFlow::Return) + break; + dwarnln("Root namespace got execution flow {}", static_cast(execution_flow)); + return BAN::Error::from_errno(EINVAL); + } + + return {}; + } + + BAN::ErrorOr Namespace::initialize_devices() + { + return {}; } } diff --git a/kernel/kernel/ACPI/AML/Node.cpp b/kernel/kernel/ACPI/AML/Node.cpp index dc1fd779..fcdae501 100644 --- a/kernel/kernel/ACPI/AML/Node.cpp +++ b/kernel/kernel/ACPI/AML/Node.cpp @@ -1,99 +1,2595 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include -namespace Kernel::ACPI +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace Kernel::ACPI::AML { - AML::ParseResult AML::ParseResult::Failure = AML::ParseResult(AML::ParseResult::Result::Failure); - AML::ParseResult AML::ParseResult::Success = AML::ParseResult(AML::ParseResult::Result::Success); + static constexpr uint64_t ONES = BAN::numeric_limits::max(); + static constexpr uint64_t ZERO = BAN::numeric_limits::min(); - uint64_t AML::Node::total_node_count = 0; - - AML::ParseResult AML::parse_object(AML::ParseContext& context) + BAN::ErrorOr parse_name_string(BAN::ConstByteSpan& aml_data) { - if (context.aml_data.size() < 1) - return ParseResult::Failure; + dprintln_if(AML_DUMP_FUNCTION_CALLS, "parse_name_string"); - if (static_cast(context.aml_data[0]) == AML::Byte::ExtOpPrefix) + if (aml_data.empty()) + return BAN::Error::from_errno(ENODATA); + + NameString name {}; + + switch (aml_data[0]) + { + case '^': + while (!aml_data.empty() && aml_data[0] == '^') { + name.base++; + aml_data = aml_data.slice(1); + } + break; + case '\\': + name.base = NameString::base_root; + aml_data = aml_data.slice(1); + break; + } + + if (aml_data.empty()) + return BAN::Error::from_errno(ENODATA); + + size_t name_seg_count = 1; + switch (aml_data[0]) + { + case 0: + name_seg_count = 0; + aml_data = aml_data.slice(1); + break; + case '.': + name_seg_count = 2; + aml_data = aml_data.slice(1); + break; + case '/': + if (aml_data.size() < 2) + return BAN::Error::from_errno(ENODATA); + name_seg_count = aml_data[1]; + aml_data = aml_data.slice(2); + break; + } + + if (aml_data.size() < name_seg_count * 4) + return BAN::Error::from_errno(ENODATA); + + TRY(name.parts.resize(name_seg_count)); + for (size_t i = 0; i < name_seg_count; i++) + { + if (!is_lead_name_char(aml_data[0]) || !is_name_char(aml_data[1]) || !is_name_char(aml_data[2]) || !is_name_char(aml_data[3])) + { + dwarnln("Invalid NameSeg {2H}, {2H}, {2H}, {2H}", + aml_data[0], aml_data[1], aml_data[2], aml_data[3] + ); + return BAN::Error::from_errno(EINVAL); + } + name.parts[i] = aml_data.as(); + aml_data = aml_data.slice(4); + } + + return name; + } + + static BAN::ErrorOr parse_integer(BAN::ConstByteSpan& aml_data) + { + dprintln_if(AML_DUMP_FUNCTION_CALLS, "parse_integer"); + + ASSERT(!aml_data.empty()); + + Node result {}; + result.type = Node::Type::Integer; + + size_t byte_count = 0; + switch (static_cast(aml_data[0])) + { + case AML::Byte::ZeroOp: + result.as.integer.value = ZERO; + break; + case AML::Byte::OneOp: + result.as.integer.value = 1; + break; + case AML::Byte::OnesOp: + result.as.integer.value = ONES; + break; + case AML::Byte::BytePrefix: + byte_count = 1; + break; + case AML::Byte::WordPrefix: + byte_count = 2; + break; + case AML::Byte::DWordPrefix: + byte_count = 4; + break; + case AML::Byte::QWordPrefix: + byte_count = 8; + break; + default: + ASSERT_NOT_REACHED(); + } + + aml_data = aml_data.slice(1); + + if (byte_count) + { + if (aml_data.size() < byte_count) + return BAN::Error::from_errno(ENODATA); + result.as.integer.value = 0; + for (size_t i = 0; i < byte_count; i++) + result.as.integer.value |= static_cast(aml_data[i]) << (i * 8); + aml_data = aml_data.slice(byte_count); + } + + return result; + } + + static BAN::ErrorOr parse_string(BAN::ConstByteSpan& aml_data) + { + dprintln_if(AML_DUMP_FUNCTION_CALLS, "parse_string"); + + ASSERT(!aml_data.empty()); + ASSERT(static_cast(aml_data[0]) == AML::Byte::StringPrefix); + aml_data = aml_data.slice(1); + + size_t len = 0; + for (; len < aml_data.size() && aml_data[len]; len++) + { + if (!(0x01 <= aml_data[len] && aml_data[len] <= 0x7F)) + { + dwarnln("Invalid byte {2H} in a string", aml_data[len]); + return BAN::Error::from_errno(EINVAL); + } + } + if (len >= aml_data.size()) + return BAN::Error::from_errno(ENODATA); + + Node result {}; + result.type = Node::Type::String; + result.as.str_buf = static_cast(kmalloc(sizeof(Buffer) + len)); + result.as.str_buf->size = len; + result.as.str_buf->ref_count = 1; + if (result.as.str_buf == nullptr) + return BAN::Error::from_errno(ENOMEM); + memcpy(result.as.str_buf->bytes, aml_data.as_span().data(), len); + + aml_data = aml_data.slice(len + 1); + + return result; + } + + BAN::ErrorOr parse_pkg(BAN::ConstByteSpan& aml_data) + { + dprintln_if(AML_DUMP_FUNCTION_CALLS, "parse_pkg"); + + if (aml_data.empty()) + return BAN::Error::from_errno(ENODATA); + + const uint32_t encoding_length = (aml_data[0] >> 6) + 1; + if (aml_data.size() < encoding_length) + return BAN::Error::from_errno(ENODATA); + + uint32_t pkg_length = 0; + switch (encoding_length) + { + case 1: + pkg_length |= aml_data[0] & 0x3F; + break; + case 2: + pkg_length |= aml_data[0] & 0x0F; + pkg_length |= aml_data[1] << 4; + break; + case 3: + pkg_length |= aml_data[0] & 0x0F; + pkg_length |= aml_data[1] << 4; + pkg_length |= aml_data[2] << 12; + break; + case 4: + pkg_length |= aml_data[0] & 0x0F; + pkg_length |= aml_data[1] << 4; + pkg_length |= aml_data[2] << 12; + pkg_length |= aml_data[3] << 20; + break; + } + + if (aml_data.size() < pkg_length) + return BAN::Error::from_errno(ENODATA); + + auto result = aml_data.slice(0, pkg_length).slice(encoding_length); + aml_data = aml_data.slice(pkg_length); + return result; + } + + static BAN::ErrorOr resolve_package_element(Package::Element& element, bool error_if_not_exists) + { + if (element.resolved) + { + if (element.value.node) + return {}; + element.value.node = new Node(); + if (element.value.node == nullptr) + return BAN::Error::from_errno(ENOMEM); + element.value.node->type = Node::Type::Uninitialized; + return {}; + } + + ASSERT(element.value.location); + auto [_, resolved_obj] = TRY(Namespace::root_namespace().find_named_object(element.value.location->scope, element.value.location->name)); + if (resolved_obj == nullptr) + { + if (!error_if_not_exists) + return {}; + dwarnln("Could not resolve '{}'.'{}'"); + return BAN::Error::from_errno(ENOENT); + } + + Node* new_node = new Node(); + if (new_node == nullptr) + return BAN::Error::from_errno(ENOMEM); + + switch (resolved_obj->node.type) + { + case Node::Type::Device: + case Node::Type::Event: + case Node::Type::Method: + case Node::Type::Mutex: + case Node::Type::OpRegion: + case Node::Type::PowerResource: + case Node::Type::Processor: + case Node::Type::ThermalZone: + case Node::Type::PredefinedScope: + new_node->type = Node::Type::Reference; + new_node->as.reference = resolved_obj; + new_node->as.reference->ref_count++; + break; + default: + *new_node = TRY(resolved_obj->node.copy()); + break; + } + + delete element.value.location; + element.resolved = true; + element.value.node = new_node; + + return {}; + } + + static BAN::ErrorOr parse_package_op(ParseContext& context) + { + dprintln_if(AML_DUMP_FUNCTION_CALLS, "parse_package_op"); + + ASSERT(!context.aml_data.empty()); + const auto opcode = static_cast(context.aml_data[0]); + context.aml_data = context.aml_data.slice(1); + + auto package_pkg = TRY(parse_pkg(context.aml_data)); + if (package_pkg.empty()) + return BAN::Error::from_errno(ENODATA); + + auto old_aml_data = context.aml_data; + context.aml_data = package_pkg; + + uint64_t num_elements = 0; + switch (opcode) + { + case AML::Byte::PackageOp: + num_elements = context.aml_data[0]; + context.aml_data = context.aml_data.slice(1); + break; + case AML::Byte::VarPackageOp: + { + auto node = TRY(parse_node(context)); + node = TRY(convert_node(BAN::move(node), ConvInteger, sizeof(uint64_t))); + num_elements = node.as.integer.value; + break; + } + default: + ASSERT_NOT_REACHED(); + } + + Node result {}; + result.type = Node::Type::Package; + result.as.package = static_cast(kmalloc(sizeof(Package) + num_elements * sizeof(Package::Element))); + if (result.as.package == nullptr) + return BAN::Error::from_errno(ENOMEM); + result.as.package->num_elements = num_elements; + result.as.package->ref_count = 1; + + size_t i = 0; + for (; i < num_elements && !context.aml_data.empty(); i++) + { + auto& element = result.as.package->elements[i]; + + if (is_name_string_start(context.aml_data[0])) + { + auto name_string = TRY(parse_name_string(context.aml_data)); + + element.resolved = false; + element.value.location = new Package::Element::Location(); + if (element.value.location == nullptr) + return BAN::Error::from_errno(ENOMEM); + element.value.location->name = BAN::move(name_string); + element.value.location->scope = TRY(context.scope.copy()); + + TRY(resolve_package_element(element, false)); + continue; + } + + element.resolved = true; + element.value.node = new Node(); + element.value.node->type = Node::Type::Uninitialized; + if (element.value.node == nullptr) + return BAN::Error::from_errno(ENOMEM); + *element.value.node = TRY(parse_node(context)); + } + for (; i < num_elements; i++) + { + result.as.package->elements[i].resolved = true; + result.as.package->elements[i].value.node = nullptr; + } + context.aml_data = old_aml_data; + + return result; + } + + static BAN::ErrorOr parse_buffer_op(ParseContext& context) + { + dprintln_if(AML_DUMP_FUNCTION_CALLS, "parse_buffer_op"); + + ASSERT(!context.aml_data.empty()); + ASSERT(static_cast(context.aml_data[0]) == AML::Byte::BufferOp); + context.aml_data = context.aml_data.slice(1); + + auto buffer_pkg = TRY(parse_pkg(context.aml_data)); + if (buffer_pkg.empty()) + return BAN::Error::from_errno(ENODATA); + + auto old_aml_data = context.aml_data; + context.aml_data = buffer_pkg; + + auto buffer_size_node = TRY(convert_node(TRY(parse_node(context)), ConvInteger, sizeof(uint64_t))); + + const uint64_t buffer_size = BAN::Math::max(buffer_size_node.as.integer.value, context.aml_data.size()); + + Node result {}; + result.type = Node::Type::Buffer; + result.as.str_buf = static_cast(kmalloc(sizeof(Buffer) + buffer_size)); + if (result.as.str_buf == nullptr) + return BAN::Error::from_errno(ENOMEM); + result.as.str_buf->size = buffer_size; + result.as.str_buf->ref_count = 1; + + if (context.aml_data.size() > 0) + memcpy(result.as.str_buf->bytes, context.aml_data.data(), context.aml_data.size()); + if (context.aml_data.size() < buffer_size) + memset(result.as.str_buf->bytes + context.aml_data.size(), 0, buffer_size - context.aml_data.size()); + + context.aml_data = old_aml_data; + + return result; + } + + static BAN::ErrorOr parse_logical_op(ParseContext& context) + { + dprintln_if(AML_DUMP_FUNCTION_CALLS, "parse_logical_op"); + + ASSERT(!context.aml_data.empty()); + const auto opcode = static_cast(context.aml_data[0]); + context.aml_data = context.aml_data.slice(1); + + Node dummy_integer {}; + dummy_integer.type = Node::Type::Integer; + dummy_integer.as.integer.value = 0; + + auto lhs = TRY(parse_node(context)); + + if (opcode == AML::Byte::LNotOp) + { + lhs = TRY(convert_node(BAN::move(lhs), ConvInteger, sizeof(uint64_t))); + + Node result {}; + result.type = Node::Type::Integer; + result.as.integer.value = lhs.as.integer.value ? ZERO : ONES; + return result; + } + + auto rhs = TRY(parse_node(context)); + + bool (*compare)(int) = nullptr; + switch (opcode) + { + case AML::Byte::LAndOp: + case AML::Byte::LOrOp: + { + lhs = TRY(convert_node(BAN::move(lhs), ConvInteger, sizeof(uint64_t))); + rhs = TRY(convert_node(BAN::move(rhs), ConvInteger, sizeof(uint64_t))); + + Node result {}; + result.type = Node::Type::Integer; + if (opcode == AML::Byte::LAndOp) + result.as.integer.value = (lhs.as.integer.value && rhs.as.integer.value) ? ONES : ZERO; + else + result.as.integer.value = (lhs.as.integer.value || rhs.as.integer.value) ? ONES : ZERO; + + return result; + } + case AML::Byte::LEqualOp: + compare = [](int val) { return val == 0; }; + break; + case AML::Byte::LLessOp: + compare = [](int val) { return val < 0; }; + break; + case AML::Byte::LGreaterOp: + compare = [](int val) { return val > 0; }; + break; + default: + ASSERT_NOT_REACHED(); + } + + lhs = TRY(convert_node(BAN::move(lhs), ConvInteger | ConvString | ConvBuffer, ONES)); + + int (*normalize)(const Node&, const Node&) = nullptr; + switch (lhs.type) + { + case Node::Type::Integer: + normalize = [](const Node& a, const Node& b) -> int { + if (a.as.integer.value == b.as.integer.value) + return 0; + return a.as.integer.value < b.as.integer.value ? -1 : 1; + }; + break; + case Node::Type::String: + case Node::Type::Buffer: + normalize = [](const Node& a, const Node& b) -> int { + const size_t bytes = BAN::Math::min(a.as.str_buf->size, b.as.str_buf->size); + if (int ret = memcmp(a.as.str_buf->bytes, b.as.str_buf->bytes, bytes)) + return ret; + return a.as.str_buf->size < b.as.str_buf->size; + }; + break; + default: + ASSERT_NOT_REACHED(); + } + + rhs = TRY(convert_node(BAN::move(rhs), lhs)); + + Node result {}; + result.type = Node::Type::Integer; + result.as.integer.value = compare(normalize(lhs, rhs)) ? ONES : ZERO; + + return result; + } + + static BAN::ErrorOr parse_index_op(ParseContext& context); + + enum class TargetType { Reference, Local, Arg, Debug }; + + using SuperNameResult = Pair; + static BAN::ErrorOr parse_super_name(ParseContext& context, bool error_if_not_exists) + { + dprintln_if(AML_DUMP_FUNCTION_CALLS, "parse_super_name"); + + auto& aml_data = context.aml_data; + + const auto opcode = static_cast(aml_data[0]); + const auto ext_opcode = static_cast(aml_data.size() >= 2 ? aml_data[1] : 0); + if (opcode == AML::Byte::IndexOp) + { + // FIXME: memory leak + + Reference* reference = new Reference(); + if (reference == nullptr) + return BAN::Error::from_errno(ENOMEM); + reference->node = TRY(parse_index_op(context)); + reference->ref_count = 1; + + return SuperNameResult { TargetType::Reference, reference }; + } + else if (is_name_string_start(aml_data[0])) + { + auto target = TRY(parse_name_string(aml_data)); + auto [_, named_object] = TRY(Namespace::root_namespace().find_named_object(context.scope, target)); + if (error_if_not_exists && named_object == nullptr) + { + dwarnln("SuperName '{}'.'{}' not found", context.scope, target); + return BAN::Error::from_errno(ENOENT); + } + return SuperNameResult { TargetType::Reference, named_object }; + } + else if (opcode == AML::Byte::ExtOpPrefix && ext_opcode == AML::ExtOp::DebugOp) + { + aml_data = aml_data.slice(2); + return SuperNameResult { TargetType::Debug, nullptr }; + } + else if (AML::Byte::Local0 <= opcode && opcode <= AML::Byte::Local7) + { + const uint8_t local_index = aml_data[0] - static_cast(AML::Byte::Local0); + aml_data = aml_data.slice(1); + ASSERT(context.locals[local_index]); + return SuperNameResult { TargetType::Local, context.locals[local_index] }; + } + else if (AML::Byte::Arg0 <= opcode && opcode <= AML::Byte::Arg6) + { + const uint8_t arg_index = aml_data[0] - static_cast(AML::Byte::Arg0); + aml_data = aml_data.slice(1); + + if (context.args[arg_index] == nullptr) { + dwarnln("Trying to reference uninitialized arg"); + return BAN::Error::from_errno(EINVAL); + } + + return SuperNameResult { TargetType::Local, context.args[arg_index] }; + } + + const bool is_ext = (opcode == AML::Byte::ExtOpPrefix) && (aml_data.size() >= 2); + dwarnln("TODO: SuperName {2H}{}", aml_data[is_ext ? 1 : 0], is_ext ? "e" : ""); + return BAN::Error::from_errno(ENOTSUP); + } + + template requires (BAN::is_same_v || BAN::is_same_v) + static BAN::ErrorOr underlying_node(T& node) + { + switch (node.type) + { + case Node::Type::Index: + dwarnln("TODO: Underlying node of index"); + return BAN::Error::from_errno(ENOTSUP); + case Node::Type::Reference: + return node.as.reference->node; + default: + return node; + } + } + + BAN::ErrorOr convert_node(Node&& source, uint8_t conversion, size_t max_length) + { + dprintln_if(AML_DUMP_FUNCTION_CALLS, "convert_node {} -> 0b{3b}", source, conversion); + + if ((source.type == Node::Type::Integer) && (conversion & Conversion::ConvInteger)) + return source; + if ((source.type == Node::Type::Buffer) && (conversion & Conversion::ConvBuffer)) + return source; + if ((source.type == Node::Type::String) && (conversion & Conversion::ConvString)) + return source; + + if (source.type == Node::Type::FieldUnit) + return convert_from_field_unit(source, conversion, max_length); + + if (conversion & Conversion::ConvInteger) + { + Node result {}; + result.type = Node::Type::Integer; + result.as.integer.value = 0; + + switch (source.type) + { + case Node::Type::String: + case Node::Type::Buffer: + memcpy( + &result.as.integer.value, + source.as.str_buf->bytes, + BAN::Math::min(source.as.str_buf->size, sizeof(uint64_t)) + ); + return result; + case Node::Type::BufferField: + for (size_t i = 0; i < BAN::Math::min(source.as.buffer_field.bit_count, 64); i++) + { + const uint64_t idx = source.as.buffer_field.bit_offset + i; + const uint64_t bit = (source.as.buffer_field.buffer->bytes[idx / 8] >> (idx % 8)) & 1; + result.as.integer.value |= bit << i; + } + return result; + default: + break; + } + } + + if (conversion & Conversion::ConvBuffer) + { + Node result {}; + result.type = Node::Type::Buffer; + result.as.str_buf = nullptr; + + switch (source.type) + { + case Node::Type::Integer: + if (source.as.integer.value) + max_length = BAN::Math::min(max_length, BAN::Math::ilog2(source.as.integer.value) / 4 + 1); + else + max_length = 1; + result.as.str_buf = static_cast(kmalloc(sizeof(Buffer) + max_length)); + if (result.as.str_buf == nullptr) + return BAN::Error::from_errno(ENOMEM); + memcpy(result.as.str_buf->bytes, &source.as.integer.value, max_length); + result.as.str_buf->size = max_length; + result.as.str_buf->ref_count = 1; + return result; + case Node::Type::String: + { + max_length = BAN::Math::min(max_length, source.as.str_buf->size + 1); + + result.as.str_buf = static_cast(kmalloc(sizeof(Buffer) + max_length)); + if (result.as.str_buf == nullptr) + return BAN::Error::from_errno(ENOMEM); + if (max_length <= source.as.str_buf->size) + memcpy(result.as.str_buf->bytes, source.as.str_buf->bytes, max_length); + else + { + memcpy(result.as.str_buf->bytes, source.as.str_buf->bytes, max_length - 1); + result.as.str_buf->bytes[max_length - 1] = 0x00; + } + result.as.str_buf->size = max_length; + result.as.str_buf->ref_count = 1; + return result; + } + case Node::Type::BufferField: + dwarnln("TODO: buffer field to buffer"); + return BAN::Error::from_errno(ENOTSUP); + default: + break; + } + } + + if (conversion & Conversion::ConvString) + { + Node result {}; + result.type = Node::Type::String; + result.as.str_buf = nullptr; + + switch (source.type) + { + case Node::Type::Integer: + { + auto string = TRY(BAN::String::formatted("{}", source.as.integer.value)); + max_length = BAN::Math::min(max_length, string.size()); + result.as.str_buf = static_cast(kmalloc(sizeof(Buffer) + max_length)); + if (result.as.str_buf == nullptr) + return BAN::Error::from_errno(ENOMEM); + memcpy(result.as.str_buf->bytes, string.data(), max_length); + result.as.str_buf->size = max_length; + result.as.str_buf->ref_count = 1; + return result; + } + case Node::Type::Buffer: + result = BAN::move(source); + result.type = Node::Type::String; + return result; + case Node::Type::BufferField: + dwarnln("TODO: buffer field to string"); + return BAN::Error::from_errno(ENOTSUP); + default: + break; + } + } + + dwarnln("Invalid conversion from {} to 0b{3b}", source, conversion); + return BAN::Error::from_errno(EINVAL); + } + + BAN::ErrorOr convert_node(Node&& source, const Node& target) + { + if (target.type == Node::Type::Uninitialized) + return source; + if (target.type == Node::Type::Integer) + return convert_node(BAN::move(source), ConvInteger, 8); + if (target.type == Node::Type::String) + return convert_node(BAN::move(source), ConvString, target.as.str_buf->size); + if (target.type == Node::Type::Buffer) + return convert_node(BAN::move(source), ConvBuffer, target.as.str_buf->size); + dwarnln("Invalid conversion from {} to {}", source, target); + return BAN::Error::from_errno(EINVAL); + } + + static BAN::ErrorOr store_to_buffer_field(const Node& source, Node& target) + { + ASSERT(target.type == Node::Type::BufferField); + + const uint64_t bit_count = target.as.buffer_field.bit_count; + const uint64_t bit_offset = target.as.buffer_field.bit_offset; + + const uint8_t* src_buf = nullptr; + uint64_t src_len = 0; + + switch (source.type) + { + case Node::Type::String: + case Node::Type::Buffer: + src_buf = source.as.str_buf->bytes; + src_len = source.as.str_buf->size; + break; + case Node::Type::Integer: + src_buf = reinterpret_cast(&source.as.integer.value); + src_len = sizeof(uint64_t); + break; + default: + { + Node dummy = TRY(convert_node(TRY(source.copy()), ConvInteger | ConvBuffer, sizeof(uint64_t))); + return store_to_buffer_field(dummy, target); + } + } + + uint64_t i = 0; + while (i < bit_count) + { + const uint64_t j = bit_offset + i; + + const uint8_t i_mod = i % 8; + const uint8_t j_mod = j % 8; + + const uint8_t max_src_bits = BAN::Math::min(8 - i_mod, bit_count - i); + const uint8_t max_dst_bits = BAN::Math::min(8 - j_mod, bit_count - i); + const uint8_t bits = BAN::Math::min(max_src_bits, max_dst_bits); + + const uint8_t mask = (1 << bits) - 1; + + const uint8_t src_byte = (i / 8 < src_len) ? src_buf[i / 8] : 0x00; + + uint8_t& dst_byte = target.as.buffer_field.buffer->bytes[j / 8]; + dst_byte &= ~(mask << j_mod); + dst_byte |= ((src_byte >> i_mod) & mask) << j_mod; + + i += bits; + } + + return {}; + } + + static BAN::ErrorOr perform_store(const Node& source, Reference* target, TargetType target_type) + { + dprintln_if(AML_DUMP_FUNCTION_CALLS, "perform_store"); + + if (target_type == TargetType::Debug) + { + dprintln_if(AML_ENABLE_DEBUG, "DEBUG: {}", source); + return {}; + } + + ASSERT(target); + + if (target->node.type == Node::Type::BufferField) + return store_to_buffer_field(source, target->node); + + if (target->node.type == Node::Type::FieldUnit) + return store_to_field_unit(source, target->node); + + auto source_copy = TRY(source.copy()); + + Node* index_node = nullptr; + if (target->node.type == Node::Type::Reference) + { + auto& ref_target = target->node.as.reference->node; + + if (ref_target.type == Node::Type::Index) + index_node = &ref_target; + else + { + ASSERT(ref_target.type != Node::Type::Reference); + ref_target = TRY(convert_node(BAN::move(source_copy), ref_target)); + return {}; + } + } + + if (target->node.type == Node::Type::Index) + index_node = &target->node; + + if (index_node) + { + auto& index = index_node->as.index; + switch (index.type) + { + case Node::Type::String: + case Node::Type::Buffer: + ASSERT(index.index < index.as.str_buf->size); + index.as.str_buf->bytes[index.index] = TRY(convert_node(BAN::move(source_copy), ConvInteger, sizeof(uint64_t))).as.integer.value; + break; + case Node::Type::Package: + { + ASSERT(index.index < index.as.package->num_elements); + + auto& pkg_element = index.as.package->elements[index.index]; + TRY(resolve_package_element(pkg_element, true)); + ASSERT(pkg_element.value.node); + + if (pkg_element.value.node->type == Node::Type::Reference) + *pkg_element.value.node = TRY(convert_node(BAN::move(source_copy), pkg_element.value.node->as.reference->node)); + else + *pkg_element.value.node = BAN::move(source_copy); + break; + } + default: + ASSERT_NOT_REACHED(); + } + + return {}; + } + + if (target_type == TargetType::Reference) + target->node = TRY(convert_node(BAN::move(source_copy), target->node)); + else + target->node = BAN::move(source_copy); + + return {}; + } + + static BAN::ErrorOr store_into_target(ParseContext& context, const Node& node) + { + dprintln_if(AML_DUMP_FUNCTION_CALLS, "store_into_target"); + + auto& aml_data = context.aml_data; + + if (aml_data.empty()) + return BAN::Error::from_errno(ENODATA); + + if (aml_data[0] == 0) + { + aml_data = aml_data.slice(1); + return {}; + } + + auto [target_type, target] = TRY(parse_super_name(context, true)); + return perform_store(node, target, target_type); + } + + static BAN::ErrorOr parse_store_op(ParseContext& context) + { + dprintln_if(AML_DUMP_FUNCTION_CALLS, "parse_store_op"); + + ASSERT(!context.aml_data.empty()); + ASSERT(static_cast(context.aml_data[0]) == AML::Byte::StoreOp); + context.aml_data = context.aml_data.slice(1); + + auto source = TRY(parse_node(context)); + + if (context.aml_data.empty()) + return BAN::Error::from_errno(ENODATA); + if (context.aml_data[0] == 0) + { + dwarnln("StoreOp in to null target"); + return BAN::Error::from_errno(EINVAL); + } + + TRY(store_into_target(context, source)); + + return source; + } + + static BAN::ErrorOr parse_copy_object_op(ParseContext& context) + { + dprintln_if(AML_DUMP_FUNCTION_CALLS, "parse_copy_object_op"); + + ASSERT(!context.aml_data.empty()); + ASSERT(static_cast(context.aml_data[0]) == AML::Byte::CopyObjectOp); + context.aml_data = context.aml_data.slice(1); + + auto source = TRY(parse_node(context)); + + if (context.aml_data.empty()) + return BAN::Error::from_errno(ENODATA); + + auto [target_type, target] = TRY(parse_super_name(context, true)); + switch (target_type) + { + case TargetType::Arg: + case TargetType::Local: + case TargetType::Reference: + break; + case TargetType::Debug: + dwarnln("CopyObjectOp target is Debug"); + return BAN::Error::from_errno(EINVAL); + } + + target->node = TRY(source.copy()); + + return source; + } + + static BAN::ErrorOr parse_index_op(ParseContext& context) + { + dprintln_if(AML_DUMP_FUNCTION_CALLS, "parse_index_op"); + + ASSERT(!context.aml_data.empty()); + ASSERT(static_cast(context.aml_data[0]) == AML::Byte::IndexOp); + context.aml_data = context.aml_data.slice(1); + + auto source_dummy = TRY(parse_node(context, true)); + auto index = TRY(convert_node(TRY(parse_node(context)), ConvInteger, sizeof(uint64_t))); + + auto& source = TRY_REF(underlying_node(source_dummy)); + + Node result {}; + + switch (source.type) + { + case Node::Type::String: + case Node::Type::Buffer: + if (index.as.integer.value >= source.as.str_buf->size) + { + dwarnln("Invalid index {} to buffer of size {}", index.as.integer.value, source.as.str_buf->size); + return BAN::Error::from_errno(EINVAL); + } + result.as.index.as.str_buf = source.as.str_buf; + result.as.index.as.str_buf->ref_count++; + break; + case Node::Type::Package: + if (index.as.integer.value >= source.as.package->num_elements) + { + dwarnln("Invalid index {} to package of size {}", index.as.integer.value, source.as.package->num_elements); + return BAN::Error::from_errno(EINVAL); + } + result.as.index.as.package = source.as.package; + result.as.index.as.package->ref_count++; + break; + default: + dwarnln("Invalid IndexOp({}, {})", source, index); + return BAN::Error::from_errno(EINVAL); + } + + result.type = Node::Type::Index; + result.as.index.type = source.type; + result.as.index.index = index.as.integer.value; + + TRY(store_into_target(context, result)); + + return result; + } + + static BAN::ErrorOr parse_object_type_op(ParseContext& context) + { + dprintln_if(AML_DUMP_FUNCTION_CALLS, "parse_object_type_op"); + + ASSERT(!context.aml_data.empty()); + ASSERT(static_cast(context.aml_data[0]) == AML::Byte::ObjectTypeOp); + context.aml_data = context.aml_data.slice(1); + + auto [object_type, object] = TRY(parse_super_name(context, true)); + + uint64_t value = 0; + if (object_type == TargetType::Debug) + value = 16; + else + { + ASSERT(object); + + auto* node = &object->node; + while (node->type == Node::Type::Reference) + if (node->type == Node::Type::Reference) + node = &node->as.reference->node; + + auto node_type = node->type; + if (node_type == Node::Type::Index) + { + const auto& index = node->as.index; + switch (index.type) + { + case Node::Type::String: + case Node::Type::Buffer: + node_type = Node::Type::BufferField; + break; + case Node::Type::Package: + ASSERT(index.index < index.as.package->num_elements); + TRY(resolve_package_element(index.as.package->elements[index.index], true)); + node_type = index.as.package->elements[index.index].value.node->type; + break; + default: + ASSERT_NOT_REACHED(); + } + } + + switch (node_type) + { + case Node::Type::Uninitialized: + case Node::Type::PredefinedScope: value = 0; break; + case Node::Type::Integer: value = 1; break; + case Node::Type::String: value = 2; break; + case Node::Type::Buffer: value = 3; break; + case Node::Type::Package: value = 4; break; + case Node::Type::FieldUnit: value = 5; break; + case Node::Type::Device: value = 6; break; + case Node::Type::Event: value = 7; break; + case Node::Type::Method: value = 8; break; + case Node::Type::Mutex: value = 9; break; + case Node::Type::OpRegion: value = 10; break; + case Node::Type::PowerResource: value = 11; break; + case Node::Type::Processor: value = 12; break; + case Node::Type::ThermalZone: value = 13; break; + case Node::Type::BufferField: value = 14; break; + case Node::Type::Debug: value = 16; break; + case Node::Type::Index: + case Node::Type::Reference: + case Node::Type::Count: ASSERT_NOT_REACHED(); + } + } + + Node result; + result.type = Node::Type::Integer; + result.as.integer.value = value; + return result; + } + + static BAN::ErrorOr sizeof_impl(const Node& node) + { + Node result {}; + result.type = Node::Type::Integer; + result.as.integer.value = 0; + + switch (node.type) + { + case Node::Type::String: + case Node::Type::Buffer: + result.as.integer.value = node.as.str_buf->size; + break; + case Node::Type::Package: + result.as.integer.value = node.as.package->num_elements; + break; + case Node::Type::Reference: + return sizeof_impl(node.as.reference->node); + default: + dwarnln("SizeofOp on {}", node); + return BAN::Error::from_errno(EINVAL); + } + + return result; + } + + static BAN::ErrorOr parse_createfield_op(ParseContext& context) + { + dprintln_if(AML_DUMP_FUNCTION_CALLS, "parse_createfield_op"); + + ASSERT(!context.aml_data.empty()); + const auto opcode = static_cast(context.aml_data[0]); + context.aml_data = context.aml_data.slice(1); + + uint64_t bit_count = 0; + bool index_in_bits = false; + + if (opcode == AML::Byte::ExtOpPrefix) + { + ASSERT(!context.aml_data.empty()); + ASSERT(static_cast(context.aml_data[0]) == AML::ExtOp::CreateFieldOp); + context.aml_data = context.aml_data.slice(1); + + bit_count = 0; + index_in_bits = true; + } + else + { + switch (opcode) + { + case AML::Byte::CreateBitFieldOp: + bit_count = 1; + index_in_bits = true; + break; + case AML::Byte::CreateByteFieldOp: + bit_count = 8; + index_in_bits = false; + break; + case AML::Byte::CreateWordFieldOp: + bit_count = 16; + index_in_bits = false; + break; + case AML::Byte::CreateDWordFieldOp: + bit_count = 32; + index_in_bits = false; + break; + case AML::Byte::CreateQWordFieldOp: + bit_count = 64; + index_in_bits = false; + break; + default: + ASSERT_NOT_REACHED(); + } + } + + auto buffer_node = TRY(parse_node(context)); + if (buffer_node.type != Node::Type::Buffer) + { + dwarnln("CreateField buffer is {}", buffer_node); + return BAN::Error::from_errno(EINVAL); + } + + Node dummy_integer {}; + dummy_integer.type = Node::Type::Integer; + dummy_integer.as.integer.value = 0; + + auto index_node = TRY(convert_node(TRY(parse_node(context)), ConvInteger, sizeof(uint64_t))); + + if (bit_count == 0) + { + auto bit_count_node = TRY(convert_node(TRY(parse_node(context)), ConvInteger, sizeof(uint64_t))); + + bit_count = bit_count_node.as.integer.value; + if (bit_count == 0) + { + dwarnln("CreateField bit count 0"); + return BAN::Error::from_errno(EINVAL); + } + } + + auto field_name_string = TRY(parse_name_string(context.aml_data)); + + Node buffer_field; + buffer_field.type = Node::Type::BufferField; + buffer_field.as.buffer_field.buffer = buffer_node.as.str_buf; + buffer_field.as.buffer_field.buffer->ref_count++; + buffer_field.as.buffer_field.bit_count = bit_count; + buffer_field.as.buffer_field.bit_offset = index_in_bits ? index_node.as.integer.value : index_node.as.integer.value * 8; + + TRY(Namespace::root_namespace().add_named_object(context.scope, field_name_string, BAN::move(buffer_field))); + + return {}; + } + + static BAN::ErrorOr parse_sizeof_op(ParseContext& context) + { + dprintln_if(AML_DUMP_FUNCTION_CALLS, "parse_sizeof_op"); + + ASSERT(!context.aml_data.empty()); + ASSERT(static_cast(context.aml_data[0]) == AML::Byte::SizeOfOp); + context.aml_data = context.aml_data.slice(1); + + auto [object_type, object] = TRY(parse_super_name(context, true)); + if (object_type == TargetType::Debug) + { + dwarnln("SizeofOp on debug object"); + return BAN::Error::from_errno(EINVAL); + } + + ASSERT(object); + return TRY(sizeof_impl(object->node)); + } + + static BAN::ErrorOr derefof_impl(const Node& source) + { + switch (source.type) + { + case Node::Type::Reference: + return TRY(source.as.reference->node.copy()); + case Node::Type::Index: + { + switch (source.as.index.type) + { + case Node::Type::String: + case Node::Type::Buffer: + { + ASSERT(source.as.index.index < source.as.index.as.str_buf->size); + + Node result; + result.type = Node::Type::Integer; + result.as.integer.value = source.as.index.as.str_buf->bytes[source.as.index.index]; + return result; + } + case Node::Type::Package: + { + ASSERT(source.as.index.index < source.as.index.as.package->num_elements); + TRY(resolve_package_element(source.as.index.as.package->elements[source.as.index.index], true)); + return TRY(source.as.index.as.package->elements[source.as.index.index].value.node->copy()); + } + default: ASSERT_NOT_REACHED(); + } + } + default: + dwarnln("DerefOf of non-reference {}", source); + return BAN::Error::from_errno(EINVAL); + } + } + + static BAN::ErrorOr parse_inc_dec_op(ParseContext& context) + { + dprintln_if(AML_DUMP_FUNCTION_CALLS, "parse_inc_dec_op"); + + ASSERT(!context.aml_data.empty()); + const uint8_t opcode = context.aml_data[0]; + context.aml_data = context.aml_data.slice(1); + + uint64_t (*function)(uint64_t) = nullptr; + switch (static_cast(opcode)) + { + case AML::Byte::IncrementOp: + function = [](uint64_t x) { return x + 1; }; + break; + case AML::Byte::DecrementOp: + function = [](uint64_t x) { return x - 1; }; + break; + default: + ASSERT_NOT_REACHED(); + } + + auto [type, addend_ref] = TRY(parse_super_name(context, true)); + if (type == TargetType::Debug) + { + dprintln_if(AML_DUMP_FUNCTION_CALLS, "UnaryIntegerOp on Debug object"); + + Node result {}; + result.type = Node::Type::Integer; + result.as.integer.value = 0; + return result; + } + + ASSERT(addend_ref); + + Node addend_node = TRY(addend_ref->node.copy()); + if (addend_node.type == Node::Type::Reference || addend_node.type == Node::Type::Index) + addend_node = TRY(derefof_impl(addend_node)); + + auto current = TRY(convert_node(BAN::move(addend_node), ConvInteger, sizeof(uint64_t))); + + Node result {}; + result.type = Node::Type::Integer; + result.as.integer.value = function(current.as.integer.value); + + TRY(perform_store(result, addend_ref, type)); + return result; + } + + static BAN::ErrorOr parse_unary_integer_op(ParseContext& context) + { + dprintln_if(AML_DUMP_FUNCTION_CALLS, "parse_unary_integer_op"); + + ASSERT(!context.aml_data.empty()); + const auto opcode = context.aml_data[0]; + context.aml_data = context.aml_data.slice(1); + + uint64_t (*function)(uint64_t) = nullptr; + + switch (static_cast(opcode)) + { + case AML::Byte::NotOp: + function = [](uint64_t a) { return ~a; }; + break; + default: + ASSERT_NOT_REACHED(); + } + + auto value = TRY(convert_node(TRY(parse_node(context)), ConvInteger, sizeof(uint64_t))); + + Node result {}; + result.type = Node::Type::Integer; + result.as.integer.value = function(value.as.integer.value); + + TRY(store_into_target(context, result)); + + return result; + } + + static BAN::ErrorOr parse_binary_integer_op(ParseContext& context) + { + dprintln_if(AML_DUMP_FUNCTION_CALLS, "parse_binary_integer_op"); + + ASSERT(!context.aml_data.empty()); + const auto opcode = static_cast(context.aml_data[0]); + context.aml_data = context.aml_data.slice(1); + + uint64_t (*function)(uint64_t, uint64_t) = nullptr; + + switch (opcode) + { + case AML::Byte::AddOp: + function = [](uint64_t a, uint64_t b) { return a + b; }; + break; + case AML::Byte::SubtractOp: + function = [](uint64_t a, uint64_t b) { return a - b; }; + break; + case AML::Byte::MultiplyOp: + function = [](uint64_t a, uint64_t b) { return a * b; }; + break; + case AML::Byte::ShiftLeftOp: + function = [](uint64_t a, uint64_t b) { return a << b; }; + break; + case AML::Byte::ShiftRightOp: + function = [](uint64_t a, uint64_t b) { return a >> b; }; + break; + case AML::Byte::AndOp: + function = [](uint64_t a, uint64_t b) { return a & b; }; + break; + case AML::Byte::NandOp: + function = [](uint64_t a, uint64_t b) { return ~(a & b); }; + break; + case AML::Byte::OrOp: + function = [](uint64_t a, uint64_t b) { return a | b; }; + break; + case AML::Byte::NorOp: + function = [](uint64_t a, uint64_t b) { return ~(a | b); }; + break; + case AML::Byte::XorOp: + function = [](uint64_t a, uint64_t b) { return a ^ b; }; + break; + case AML::Byte::DivideOp: + function = [](uint64_t a, uint64_t b) { return a / b; }; + break; + case AML::Byte::ModOp: + function = [](uint64_t a, uint64_t b) { return a % b; }; + break; + default: + ASSERT_NOT_REACHED(); + } + + auto lhs = TRY(convert_node(TRY(parse_node(context)), ConvInteger, sizeof(uint64_t))); + auto rhs = TRY(convert_node(TRY(parse_node(context)), ConvInteger, sizeof(uint64_t))); + + if (opcode == AML::Byte::DivideOp || opcode == AML::Byte::ModOp) + { + if (rhs.as.integer.value == 0) + { + dwarnln("DivideOp or ModOp divisor is zero"); + return BAN::Error::from_errno(EINVAL); + } + } + + Node result {}; + result.type = Node::Type::Integer; + result.as.integer.value = function(lhs.as.integer.value, rhs.as.integer.value); + + TRY(store_into_target(context, result)); + + if (opcode == AML::Byte::DivideOp) + { + Node remainder {}; + remainder.type = Node::Type::Integer; + remainder.as.integer.value = function(lhs.as.integer.value, rhs.as.integer.value); + TRY(store_into_target(context, remainder)); + } + + return result; + } + + static BAN::ErrorOr parse_mid_op(ParseContext& context) + { + dprintln_if(AML_DUMP_FUNCTION_CALLS, "parse_mid_op"); + + ASSERT(!context.aml_data.empty()); + ASSERT(static_cast(context.aml_data[0]) == AML::Byte::MidOp); + context.aml_data = context.aml_data.slice(1); + + auto source = TRY(convert_node(TRY(parse_node(context)), ConvBuffer | ConvString, ONES)); + const uint64_t index = TRY(convert_node(TRY(parse_node(context)), ConvInteger, sizeof(uint64_t))).as.integer.value; + const uint64_t length = TRY(convert_node(TRY(parse_node(context)), ConvInteger, sizeof(uint64_t))).as.integer.value; + + const uint64_t source_len = source.as.str_buf->size; + + uint64_t result_size = 0; + if (index + length <= source_len) + result_size = length; + else if (index < source_len) + result_size = source_len - index; + + Node result; + result.type = source.type; + result.as.str_buf = static_cast(kmalloc(sizeof(Buffer) + result_size)); + if (result.as.str_buf == nullptr) + return BAN::Error::from_errno(ENOTSUP); + memcpy(result.as.str_buf->bytes, source.as.str_buf->bytes + index, result_size); + result.as.str_buf->size = result_size; + result.as.str_buf->ref_count = 1; + + return result; + } + + static BAN::ErrorOr parse_concat_op(ParseContext& context) + { + dprintln_if(AML_DUMP_FUNCTION_CALLS, "parse_concat_op"); + + ASSERT(!context.aml_data.empty()); + ASSERT(static_cast(context.aml_data[0]) == AML::Byte::ConcatOp); + context.aml_data = context.aml_data.slice(1); + + auto source1 = TRY(convert_node(TRY(parse_node(context)), ConvInteger | ConvString | ConvBuffer, ONES)); + auto source2 = TRY(convert_node(TRY(parse_node(context)), source1)); + + Node result {}; + switch (source1.type) + { + case AML::Node::Type::Integer: + dwarnln("TODO: ConcatOp with integers"); + return BAN::Error::from_errno(ENOTSUP); + case AML::Node::Type::String: + case AML::Node::Type::Buffer: + result.type = source1.type; + result.as.str_buf = static_cast(kmalloc(sizeof(Buffer) + source1.as.str_buf->size + source2.as.str_buf->size)); + if (result.as.str_buf == nullptr) + return BAN::Error::from_errno(ENOMEM); + result.as.str_buf->size = source1.as.str_buf->size + source2.as.str_buf->size; + result.as.str_buf->ref_count = 1; + memcpy(result.as.str_buf->bytes, source1.as.str_buf->bytes, source1.as.str_buf->size); + memcpy(result.as.str_buf->bytes + source1.as.str_buf->size, source2.as.str_buf->bytes, source2.as.str_buf->size); + break; + default: + ASSERT_NOT_REACHED(); + } + + TRY(store_into_target(context, result)); + + return result; + } + + static BAN::ErrorOr parse_explicit_conversion(ParseContext& context) + { + dprintln_if(AML_DUMP_FUNCTION_CALLS, "parse_explicit_conversion"); + + ASSERT(!context.aml_data.empty()); + const uint8_t opcode = context.aml_data[0]; + context.aml_data = context.aml_data.slice(1); + + auto source = TRY(parse_node(context)); + if (source.type == Node::Type::FieldUnit || source.type == Node::Type::BufferField) + source = TRY(convert_node(BAN::move(source), ConvInteger | ConvBuffer, ONES)); + + switch (source.type) + { + case Node::Type::Buffer: + case Node::Type::String: + case Node::Type::Integer: + break; + default: + dwarnln("Explicit conversion source is {}", source); + return BAN::Error::from_errno(EINVAL); + } + + Node result {}; + + switch (static_cast(opcode)) + { + case AML::Byte::ToDecimalStringOp: + if (source.type == Node::Type::String) + result = BAN::move(source); + else + { + BAN::String ban_string; + + if (source.type == Node::Type::Integer) + ban_string = TRY(BAN::String::formatted("{}", source.as.integer.value)); + else if (source.type == Node::Type::Buffer) + for (size_t i = 0; i < source.as.str_buf->size; i++) + TRY(ban_string.append(TRY(BAN::String::formatted("{},", source.as.str_buf->bytes[i])))); + else + ASSERT_NOT_REACHED(); + + if (!ban_string.empty() && ban_string.back() == ',') + ban_string.pop_back(); + + result.type = Node::Type::String; + result.as.str_buf = static_cast(kmalloc(sizeof(Buffer) + ban_string.size())); + if (result.as.str_buf == nullptr) + return BAN::Error::from_errno(EINVAL); + memcpy(result.as.str_buf->bytes, ban_string.data(), ban_string.size()); + result.as.str_buf->size = ban_string.size(); + result.as.str_buf->ref_count = 1; + } + break; + case AML::Byte::ToHexStringOp: + if (source.type == Node::Type::String) + result = BAN::move(source); + else + { + BAN::String ban_string; + + if (source.type == Node::Type::Integer) + ban_string = TRY(BAN::String::formatted("0x{H}", source.as.integer.value)); + else if (source.type == Node::Type::Buffer) + for (size_t i = 0; i < source.as.str_buf->size; i++) + TRY(ban_string.append(TRY(BAN::String::formatted("0x{2H},", source.as.str_buf->bytes[i])))); + else + ASSERT_NOT_REACHED(); + + if (!ban_string.empty() && ban_string.back() == ',') + ban_string.pop_back(); + + result.type = Node::Type::String; + result.as.str_buf = static_cast(kmalloc(sizeof(Buffer) + ban_string.size())); + if (result.as.str_buf == nullptr) + return BAN::Error::from_errno(EINVAL); + memcpy(result.as.str_buf->bytes, ban_string.data(), ban_string.size()); + result.as.str_buf->size = ban_string.size(); + result.as.str_buf->ref_count = 1; + } + break; + case AML::Byte::ToIntegerOp: + if (source.type != Node::Type::String) + result = TRY(convert_node(BAN::move(source), ConvInteger, sizeof(uint64_t))); + else + { + const auto get_base_val = + [](char c, uint8_t base) -> BAN::Optional + { + if (isdigit(c) && c - '0' < base) + return c - '0'; + if (isalpha(c) && tolower(c) - 'a' + 10 < base) + return tolower(c) - 'a' + 10; + return {}; + }; + + auto source_sv = BAN::StringView( + reinterpret_cast(source.as.str_buf->bytes), + source.as.str_buf->size + ); + + while (!source_sv.empty() && !isdigit(source_sv[0]) && source_sv[0] != '-' && source_sv[0] != '+') + source_sv = source_sv.substring(1); + + const bool is_negative = source_sv.empty() ? false : source_sv[0] == '-'; + if (!source_sv.empty() && (source_sv[0] == '-' || source_sv[0] == '+')) + source_sv = source_sv.substring(1); + + uint8_t base = 10; + if (!source_sv.empty() && source_sv[0] == '0') + { + base = 8; + source_sv = source_sv.substring(1); + if (!source_sv.empty() && tolower(source_sv[0]) == 'x') + { + base = 16; + source_sv = source_sv.substring(1); + } + } + + uint64_t value = 0; + for (size_t i = 0; i < source_sv.size(); i++) + { + const auto to_add = get_base_val(source_sv[i], base); + if (!to_add.has_value()) + break; + + if (BAN::Math::will_multiplication_overflow(value, base) || + BAN::Math::will_addition_overflow(value * base, to_add.value())) + { + value = BAN::numeric_limits::max(); + break; + } + + value = (value * base) + to_add.value(); + } + + if (is_negative) + value = -value; + + result.type = Node::Type::Integer; + result.as.integer.value = value; + } + break; + case AML::Byte::ToBufferOp: + result = TRY(convert_node(BAN::move(source), ConvBuffer, ONES)); + break; + default: + ASSERT_NOT_REACHED(); + } + + TRY(store_into_target(context, result)); + + return result; + } + + static BAN::ErrorOr parse_alias_op(ParseContext& context) + { + dprintln_if(AML_DUMP_FUNCTION_CALLS, "parse_alias_op"); + + ASSERT(!context.aml_data.empty()); + ASSERT(static_cast(context.aml_data[0]) == AML::Byte::AliasOp); + context.aml_data = context.aml_data.slice(1); + + auto source_name_string = TRY(parse_name_string(context.aml_data)); + auto object_name_string = TRY(parse_name_string(context.aml_data)); + + auto [_, source_ref] = TRY(Namespace::root_namespace().find_named_object(context.scope, source_name_string)); + if (source_ref == nullptr) + { + dwarnln("AliasOp source does not exists"); + return {}; + } + + TRY(Namespace::root_namespace().add_named_object(context.scope, object_name_string, source_ref)); + + return {}; + } + + static BAN::ErrorOr parse_name_op(ParseContext& context) + { + dprintln_if(AML_DUMP_FUNCTION_CALLS, "parse_name_op"); + + ASSERT(!context.aml_data.empty()); + ASSERT(static_cast(context.aml_data[0]) == AML::Byte::NameOp); + context.aml_data = context.aml_data.slice(1); + + auto name_string = TRY(parse_name_string(context.aml_data)); + auto object = TRY(parse_node(context)); + + auto path = TRY(Namespace::root_namespace().add_named_object(context.scope, name_string, BAN::move(object))); + if (!path.parts.empty()) + TRY(context.created_nodes.push_back(BAN::move(path))); + + return {}; + } + + static BAN::ErrorOr parse_refof_op(ParseContext& context) + { + dprintln_if(AML_DUMP_FUNCTION_CALLS, "parse_refof_op"); + + ASSERT(!context.aml_data.empty()); + ASSERT(static_cast(context.aml_data[0]) == AML::Byte::RefOfOp); + context.aml_data = context.aml_data.slice(1); + + auto [type, target] = TRY(parse_super_name(context, true)); + if (type == TargetType::Debug) + { + dwarnln("TODO: RefOf debug"); + return BAN::Error::from_errno(ENOTSUP); + } + + Reference* to_reference = target; + if (target->node.type == Node::Type::Reference) + to_reference = target->node.as.reference; + + Node result {}; + result.type = Node::Type::Reference; + result.as.reference = to_reference; + result.as.reference->ref_count++; + return result; + } + + static BAN::ErrorOr parse_condrefof_op(ParseContext& context) + { + dprintln_if(AML_DUMP_FUNCTION_CALLS, "parse_cond_refof_op"); + + 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::CondRefOfOp); + context.aml_data = context.aml_data.slice(2); + + auto [source_type, source] = TRY(parse_super_name(context, false)); + if (source_type == TargetType::Debug) + { + dwarnln("TODO: CondRefOf debug"); + return BAN::Error::from_errno(ENOTSUP); + } + + if (context.aml_data.empty()) + return BAN::Error::from_errno(ENODATA); + + if (context.aml_data[0] == 0x00) + context.aml_data = context.aml_data.slice(1); + else + { + auto [target_type, target] = TRY(parse_super_name(context, true)); + + if (source) + { + Node reference {}; + reference.type = Node::Type::Reference; + reference.as.reference = source; + reference.as.reference->ref_count++; + TRY(perform_store(reference, target, target_type)); + } + } + + Node result {}; + result.type = Node::Type::Integer; + result.as.integer.value = source ? ONES : ZERO; + return result; + } + + static BAN::ErrorOr parse_derefof_op(ParseContext& context) + { + dprintln_if(AML_DUMP_FUNCTION_CALLS, "parse_derefof_op"); + + ASSERT(!context.aml_data.empty()); + ASSERT(static_cast(context.aml_data[0]) == AML::Byte::DerefOfOp); + context.aml_data = context.aml_data.slice(1); + + return derefof_impl(TRY(parse_node(context))); + } + + static BAN::ErrorOr parse_scope_contents(Scope&& scope, BAN::ConstByteSpan aml_data) + { + ParseContext scope_context; + scope_context.scope = BAN::move(scope); + scope_context.aml_data = aml_data; + scope_context.call_depth = 0; + + while (!scope_context.aml_data.empty()) + { + auto parse_result = parse_node_or_execution_flow(scope_context); + if (parse_result.is_error()) + { + dwarnln("Failed to parse scope {}: {}", scope_context.scope, parse_result.error()); + return parse_result.release_error(); + } + + auto [execution_flow, node] = parse_result.release_value(); + if (execution_flow != ExecutionFlow::Normal) + { + dwarnln("Scope got execution flow {}", static_cast(execution_flow)); + return BAN::Error::from_errno(EINVAL); + } + } + + return {}; + } + + static BAN::ErrorOr parse_scope_op(ParseContext& context) + { + dprintln_if(AML_DUMP_FUNCTION_CALLS, "parse_scope_op"); + + ASSERT(!context.aml_data.empty()); + ASSERT(static_cast(context.aml_data[0]) == AML::Byte::ScopeOp); + context.aml_data = context.aml_data.slice(1); + + auto scope_pkg = TRY(parse_pkg(context.aml_data)); + auto scope_name = TRY(parse_name_string(scope_pkg)); + + auto [object_path, object] = TRY(Namespace::root_namespace().find_named_object(context.scope, scope_name)); + if (object == nullptr) + { + dwarnln("ScopeOp scope '{}'.'{}' does not exists", context.scope, scope_name); + return {}; + } + + switch (object->node.type) + { + case Node::Type::Device: + case Node::Type::Processor: + case Node::Type::PowerResource: + case Node::Type::ThermalZone: + case Node::Type::PredefinedScope: + break; + default: + dwarnln("ScopeOp on non-scope object"); + return BAN::Error::from_errno(EINVAL); + } + + TRY(parse_scope_contents(BAN::move(object_path), scope_pkg)); + return {}; + } + + static BAN::ErrorOr parse_notify_op(ParseContext& context) + { + dprintln_if(AML_DUMP_FUNCTION_CALLS, "parse_scope_op"); + + ASSERT(!context.aml_data.empty()); + ASSERT(static_cast(context.aml_data[0]) == AML::Byte::NotifyOp); + context.aml_data = context.aml_data.slice(1); + + auto object = TRY(parse_super_name(context, true)); + auto value = TRY(convert_node(TRY(parse_node(context)), ConvInteger, sizeof(uint64_t))); + + dwarnln("TODO: handle notify({}, {})", object.elem2->node, value); + + return {}; + } + + static BAN::ErrorOr parse_event_op(ParseContext& context) + { + dprintln_if(AML_DUMP_FUNCTION_CALLS, "parse_device_op"); + + 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 event_name = TRY(parse_name_string(context.aml_data)); + + Node event_node {}; + event_node.type = Node::Type::Event; + event_node.as.event.signal_count = 0; + + auto absolute_path = TRY(Namespace::root_namespace().add_named_object(context.scope, event_name, BAN::move(event_node))); + if (absolute_path.parts.empty()) + { + dwarnln("Could not add Device '{}'.'{}' to namespace", context.scope, event_name); + return {}; + } + + return {}; + } + + static BAN::ErrorOr parse_reset_signal_op(ParseContext& context) + { + dprintln_if(AML_DUMP_FUNCTION_CALLS, "parse_reset_signal_op"); + + ASSERT(context.aml_data.size() >= 2); + ASSERT(static_cast(context.aml_data[0]) == AML::Byte::ExtOpPrefix); + const auto opcode = static_cast(context.aml_data[1]); + context.aml_data = context.aml_data.slice(2); + + auto [_, event_ref] = TRY(parse_super_name(context, true)); + if (event_ref == nullptr) + { + dwarnln("ResetOp/SignalOp event is null"); + return BAN::Error::from_errno(EINVAL); + } + if (event_ref->node.type != Node::Type::Event) + { + dwarnln("ResetOp/SignalOp Object '{}' is not an event", event_ref->node); + return BAN::Error::from_errno(EINVAL); + } + + switch (opcode) + { + case AML::ExtOp::ResetOp: + event_ref->node.as.event.signal_count = 0; + break; + case AML::ExtOp::SignalOp: + event_ref->node.as.event.signal_count++; + break; + default: + ASSERT_NOT_REACHED(); + } + + return {}; + } + + + static BAN::ErrorOr parse_wait_op(ParseContext& context) + { + dprintln_if(AML_DUMP_FUNCTION_CALLS, "parse_wait_op"); + + 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::WaitOp); + context.aml_data = context.aml_data.slice(2); + + auto [_, event_ref] = TRY(parse_super_name(context, true)); + if (event_ref == nullptr) + { + dwarnln("WaitOp event is null"); + return BAN::Error::from_errno(EINVAL); + } + if (event_ref->node.type != Node::Type::Event) + { + dwarnln("WaitOp Object '{}' is not an event", event_ref->node); + return BAN::Error::from_errno(EINVAL); + } + + const uint64_t timeout_ms = TRY(convert_node(TRY(parse_node(context)), ConvInteger, sizeof(uint64_t))).as.integer.value; + const uint64_t wake_time_ms = (timeout_ms >= 0xFFFF) ? BAN::numeric_limits::max() : SystemTimer::get().ms_since_boot() + timeout_ms; + + uint64_t return_value = 0; + for (;;) + { + if (event_ref->node.as.event.signal_count > 0) + { + event_ref->node.as.event.signal_count--; + return_value = ZERO; + break; + } + + if (wake_time_ms >= SystemTimer::get().ms_since_boot()) + { + return_value = ONES; + break; + } + + Processor::yield(); + } + + Node result; + result.type = Node::Type::Integer; + result.as.integer.value = return_value; + return result; + } + + static BAN::ErrorOr parse_sleep_op(ParseContext& context) + { + dprintln_if(AML_DUMP_FUNCTION_CALLS, "parse_sleep_op"); + + 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::SleepOp); + context.aml_data = context.aml_data.slice(2); + + auto milliseconds = TRY(convert_node(TRY(parse_node(context)), ConvInteger, sizeof(uint64_t))); + + const uint64_t wakeup_ms = SystemTimer::get().ms_since_boot() + milliseconds.as.integer.value; + for (uint64_t curr_ms = SystemTimer::get().ms_since_boot(); curr_ms < wakeup_ms; curr_ms = SystemTimer::get().ms_since_boot()) + SystemTimer::get().sleep_ms(wakeup_ms - curr_ms); + + return {}; + } + + static BAN::ErrorOr parse_stall_op(ParseContext& context) + { + dprintln_if(AML_DUMP_FUNCTION_CALLS, "parse_stall_op"); + + 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::StallOp); + context.aml_data = context.aml_data.slice(2); + + const auto microseconds = TRY(convert_node(TRY(parse_node(context)), ConvInteger, sizeof(uint64_t))).as.integer.value; + + if (microseconds > 100) + { + dwarnln("Stall for {} us", microseconds); + return BAN::Error::from_errno(EINVAL); + } + + const uint64_t wakeup_ns = SystemTimer::get().ns_since_boot() + microseconds * 1000; + while (SystemTimer::get().ns_since_boot() < wakeup_ns) + Processor::pause(); + + return {}; + } + + static BAN::ErrorOr parse_device_op(ParseContext& context) + { + dprintln_if(AML_DUMP_FUNCTION_CALLS, "parse_device_op"); + + 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::DeviceOp); + context.aml_data = context.aml_data.slice(2); + + auto device_pkg = TRY(parse_pkg(context.aml_data)); + auto device_name = TRY(parse_name_string(device_pkg)); + + Node device_node {}; + device_node.type = Node::Type::Device; + + auto absolute_path = TRY(Namespace::root_namespace().add_named_object(context.scope, device_name, BAN::move(device_node))); + if (absolute_path.parts.empty()) + { + dwarnln("Could not add Device '{}'.'{}' to namespace", context.scope, device_name); + return {}; + } + + TRY(parse_scope_contents(BAN::move(absolute_path), device_pkg)); + return {}; + } + + static BAN::ErrorOr parse_processor_op(ParseContext& context) + { + dprintln_if(AML_DUMP_FUNCTION_CALLS, "parse_processor_op"); + + 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::ProcessorOp); + context.aml_data = context.aml_data.slice(2); + + auto processor_pkg = TRY(parse_pkg(context.aml_data)); + auto processor_name = TRY(parse_name_string(processor_pkg)); + + // FIXME: do something with ProcID, PblkAddr, PblkLen? + if (processor_pkg.size() < 6) + return BAN::Error::from_errno(ENODATA); + processor_pkg = processor_pkg.slice(6); + + Node processor_node {}; + processor_node.type = Node::Type::Processor; + + auto absolute_path = TRY(Namespace::root_namespace().add_named_object(context.scope, processor_name, BAN::move(processor_node))); + if (absolute_path.parts.empty()) + { + dwarnln("Could not add Processor '{}'.'{}' to namespace", context.scope, processor_name); + return {}; + } + + TRY(parse_scope_contents(BAN::move(absolute_path), processor_pkg)); + return {}; + } + + static BAN::ErrorOr parse_power_resource_op(ParseContext& context) + { + dprintln_if(AML_DUMP_FUNCTION_CALLS, "parse_power_resource_op"); + + 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::PowerResOp); + context.aml_data = context.aml_data.slice(2); + + auto power_resource_pkg = TRY(parse_pkg(context.aml_data)); + auto power_resource_name = TRY(parse_name_string(power_resource_pkg)); + + // FIXME: do something with SystemLevel, ResourceOrder? + if (power_resource_pkg.size() < 3) + return BAN::Error::from_errno(ENODATA); + power_resource_pkg = power_resource_pkg.slice(3); + + Node power_resource_node {}; + power_resource_node.type = Node::Type::PowerResource; + + auto absolute_path = TRY(Namespace::root_namespace().add_named_object(context.scope, power_resource_name, BAN::move(power_resource_node))); + if (absolute_path.parts.empty()) + { + dwarnln("Could not add Processor '{}'.'{}' to namespace", context.scope, power_resource_name); + return {}; + } + + TRY(parse_scope_contents(BAN::move(absolute_path), power_resource_pkg)); + return {}; + } + + static BAN::ErrorOr parse_thermal_zone_op(ParseContext& context) + { + dprintln_if(AML_DUMP_FUNCTION_CALLS, "parse_thermal_zone_op"); + + 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::ThermalZoneOp); + context.aml_data = context.aml_data.slice(2); + + auto thermal_zone_pkg = TRY(parse_pkg(context.aml_data)); + auto thermal_zone_name = TRY(parse_name_string(thermal_zone_pkg)); + + Node thermal_zone_node {}; + thermal_zone_node.type = Node::Type::ThermalZone; + + auto absolute_path = TRY(Namespace::root_namespace().add_named_object(context.scope, thermal_zone_name, BAN::move(thermal_zone_node))); + if (absolute_path.parts.empty()) + { + dwarnln("Could not add Thermal Zone '{}'.'{}' to namespace", context.scope, thermal_zone_name); + return {}; + } + + TRY(parse_scope_contents(BAN::move(absolute_path), thermal_zone_pkg)); + return {}; + } + + static BAN::ErrorOr parse_mutex_op(ParseContext& context) + { + dprintln_if(AML_DUMP_FUNCTION_CALLS, "parse_mutex_op"); + + 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::MutexOp); + context.aml_data = context.aml_data.slice(2); + + auto mutex_name = TRY(parse_name_string(context.aml_data)); + if (context.aml_data.empty()) + return BAN::Error::from_errno(ENODATA); + const uint8_t mutex_flags = context.aml_data[0]; + context.aml_data = context.aml_data.slice(1); + + if (mutex_flags & 0xF0) + { + dwarnln("MutexOp flags has bits in top nibble set"); + return BAN::Error::from_errno(EINVAL); + } + + Node mutex; + mutex.type = Node::Type::Mutex; + mutex.as.mutex = new Mutex(); + if (mutex.as.mutex == nullptr) + return BAN::Error::from_errno(ENOMEM); + mutex.as.mutex->sync_level = mutex_flags; + mutex.as.mutex->global_lock = false; + + TRY(Namespace::root_namespace().add_named_object(context.scope, mutex_name, BAN::move(mutex))); + return {}; + } + + static BAN::ErrorOr parse_fatal_op(ParseContext& context) + { + dprintln_if(AML_DUMP_FUNCTION_CALLS, "parse_fatal_op"); + + 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::FatalOp); + context.aml_data = context.aml_data.slice(2); + + if (context.aml_data.size() < 5) + return BAN::Error::from_errno(ENODATA); + + const uint8_t fatal_type = context.aml_data[0]; + + const uint32_t fatal_code = 0 + | ((uint32_t)context.aml_data[1] << 0) + | ((uint32_t)context.aml_data[2] << 8) + | ((uint32_t)context.aml_data[3] << 16) + | ((uint32_t)context.aml_data[4] << 24); + + context.aml_data = context.aml_data.slice(5); + + const auto fatal_arg = TRY(parse_node(context)); + + derrorln("FATAL: type {2H}, code {8H}, arg {}", fatal_type, fatal_code, fatal_arg); + + return {}; + } + + static BAN::ErrorOr parse_acquire_op(ParseContext& context) + { + dprintln_if(AML_DUMP_FUNCTION_CALLS, "parse_acquire_op"); + + 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::AcquireOp); + context.aml_data = context.aml_data.slice(2); + + auto [type, sync_object] = TRY(parse_super_name(context, true)); + if (type == TargetType::Debug) + { + dwarnln("AquireOp sync object is Debug"); + return BAN::Error::from_errno(EINVAL); + } + + ASSERT(sync_object); + if (sync_object->node.type != Node::Type::Mutex) + { + dwarnln("AquireOp sync object is {}", sync_object->node); + return BAN::Error::from_errno(EINVAL); + } + + if (context.aml_data.size() < 2) + return BAN::Error::from_errno(ENODATA); + + const uint16_t timeout_ms = context.aml_data.as(); + context.aml_data = context.aml_data.slice(2); + + Node result; + result.type = Node::Type::Integer; + result.as.integer.value = BAN::numeric_limits::max(); + + const uint64_t wake_time_ms = (timeout_ms >= 0xFFFF) + ? BAN::numeric_limits::max() + : SystemTimer::get().ms_since_boot() + timeout_ms; + + result.as.integer.value = 0; + while (true) + { + if (sync_object->node.as.mutex->mutex.try_lock()) + break; + if (SystemTimer::get().ms_since_boot() >= wake_time_ms) + return result; + SystemTimer::get().sleep_ms(1); + } + + if (sync_object->node.as.mutex->global_lock) + ACPI::acquire_global_lock(); + + result.as.integer.value = 0; + return result; + } + + static BAN::ErrorOr parse_release_op(ParseContext& context) + { + dprintln_if(AML_DUMP_FUNCTION_CALLS, "parse_release_op"); + + 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::ReleaseOp); + context.aml_data = context.aml_data.slice(2); + + auto [type, sync_object] = TRY(parse_super_name(context, true)); + if (type == TargetType::Debug) + { + dwarnln("AquireOp sync object is Debug"); + return BAN::Error::from_errno(EINVAL); + } + + ASSERT(sync_object); + if (sync_object->node.type != Node::Type::Mutex) + { + dwarnln("AquireOp sync object is {}", sync_object->node); + return BAN::Error::from_errno(EINVAL); + } + + if (sync_object->node.as.mutex->global_lock) + ACPI::release_global_lock(); + + sync_object->node.as.mutex->mutex.unlock(); + + return {}; + } + + static BAN::ErrorOr parse_method_op(ParseContext& context) + { + dprintln_if(AML_DUMP_FUNCTION_CALLS, "parse_method_op"); + + ASSERT(!context.aml_data.empty()); + ASSERT(static_cast(context.aml_data[0]) == AML::Byte::MethodOp); + context.aml_data = context.aml_data.slice(1); + + auto method_pkg = TRY(parse_pkg(context.aml_data)); + auto method_name = TRY(parse_name_string(method_pkg)); + if (method_pkg.empty()) + return BAN::Error::from_errno(ENODATA); + const uint8_t method_flags = method_pkg[0]; + method_pkg = method_pkg.slice(1); + + Node method_node {}; + method_node.type = Node::Type::Method; + method_node.as.method.start = method_pkg.data(); + method_node.as.method.length = method_pkg.size(); + method_node.as.method.arg_count = method_flags & 0x07; + method_node.as.method.serialized = !!(method_flags & 0x80); + method_node.as.method.mutex = nullptr; + if (method_node.as.method.serialized) + { + method_node.as.method.mutex = new Mutex(); + method_node.as.method.mutex->sync_level = method_flags >> 4; + method_node.as.method.mutex->global_lock = false; + method_node.as.method.mutex->ref_count = 1; + } + + auto path = TRY(Namespace::root_namespace().add_named_object(context.scope, method_name, BAN::move(method_node))); + if (!path.parts.empty()) + TRY(context.created_nodes.push_back(BAN::move(path))); + + return {}; + } + + static BAN::ErrorOr parse_if_op(ParseContext& context) + { + dprintln_if(AML_DUMP_FUNCTION_CALLS, "parse_if_op"); + + ASSERT(!context.aml_data.empty()); + ASSERT(static_cast(context.aml_data[0]) == AML::Byte::IfOp); + context.aml_data = context.aml_data.slice(1); + + auto if_pkg = TRY(parse_pkg(context.aml_data)); + + auto old_aml_data = context.aml_data; + context.aml_data = if_pkg; + + auto predicate_node = TRY(convert_node(TRY(parse_node(context)), ConvInteger, sizeof(uint64_t))); + const bool predicate = predicate_node.as.integer.value; + + BAN::ConstByteSpan code_path; + if (predicate) + code_path = context.aml_data; + + if (!old_aml_data.empty() && static_cast(old_aml_data[0]) == AML::Byte::ElseOp) + { + old_aml_data = old_aml_data.slice(1); + auto else_pkg = TRY(parse_pkg(old_aml_data)); + if (!predicate) + code_path = else_pkg; + } + + Node return_value {}; + ExecutionFlow execution_flow = ExecutionFlow::Normal; + + context.aml_data = code_path; + while (!context.aml_data.empty() && execution_flow == ExecutionFlow::Normal) + { + auto parse_result = parse_node_or_execution_flow(context); + if (parse_result.is_error()) + { + dwarnln("Failed to parse if body in {}: {}", context.scope, parse_result.error()); + return parse_result.release_error(); + } + + auto [new_execution_flow, node] = parse_result.release_value(); + execution_flow = new_execution_flow; + + switch (execution_flow) + { + case ExecutionFlow::Normal: + break; + case ExecutionFlow::Break: + break; + case ExecutionFlow::Continue: + break; + case ExecutionFlow::Return: + ASSERT(node.has_value()); + return_value = node.release_value(); + break; + } + } + context.aml_data = old_aml_data; + + return ExecutionFlowResult { + .elem1 = execution_flow, + .elem2 = BAN::move(return_value), + }; + } + + static BAN::ErrorOr parse_while_op(ParseContext& context) + { + dprintln_if(AML_DUMP_FUNCTION_CALLS, "parse_while_op"); + + ASSERT(!context.aml_data.empty()); + ASSERT(static_cast(context.aml_data[0]) == AML::Byte::WhileOp); + context.aml_data = context.aml_data.slice(1); + + auto while_pkg = TRY(parse_pkg(context.aml_data)); + + auto old_aml_data = context.aml_data; + + Node return_value {}; + ExecutionFlow execution_flow = ExecutionFlow::Normal; + + const uint64_t while_loop_start_ms = SystemTimer::get().ms_since_boot(); + while (execution_flow == ExecutionFlow::Normal) + { + if (auto current_ms = SystemTimer::get().ms_since_boot(); current_ms >= while_loop_start_ms + 5000) + { + dwarnln("While loop terminated after {} ms", current_ms - while_loop_start_ms); + break; + } + + context.aml_data = while_pkg; + + auto predicate = TRY(convert_node(TRY(parse_node(context)), ConvInteger, sizeof(uint64_t))); + if (predicate.as.integer.value == 0) + break; + + while (!context.aml_data.empty() && execution_flow == ExecutionFlow::Normal) + { + auto parse_result = parse_node_or_execution_flow(context); + if (parse_result.is_error()) + { + dwarnln("Failed to parse while body in {}: {}", context.scope, parse_result.error()); + return parse_result.release_error(); + } + + auto [new_execution_flow, node] = parse_result.release_value(); + execution_flow = new_execution_flow; + + switch (execution_flow) + { + case ExecutionFlow::Normal: + break; + case ExecutionFlow::Break: + break; + case ExecutionFlow::Continue: + break; + case ExecutionFlow::Return: + ASSERT(node.has_value()); + return_value = node.release_value(); + break; + } + } + + if (execution_flow == ExecutionFlow::Continue) + execution_flow = ExecutionFlow::Normal; + } + + context.aml_data = old_aml_data; + + if (execution_flow == ExecutionFlow::Break) + execution_flow = ExecutionFlow::Normal; + + return ExecutionFlowResult { + .elem1 = execution_flow, + .elem2 = BAN::move(return_value), + }; + } + + static BAN::ErrorOr parse_load_op(ParseContext& context) + { + dprintln_if(AML_DUMP_FUNCTION_CALLS, "parse_load_op"); + + 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::LoadOp); + context.aml_data = context.aml_data.slice(2); + + auto load_name = TRY(parse_name_string(context.aml_data)); + auto [named_object_path, named_object] = TRY(Namespace::root_namespace().find_named_object(context.scope, load_name)); + + Node result; + result.type = Node::Type::Integer; + result.as.integer.value = 0; + + if (named_object == nullptr) + dwarnln("Load target does not exist"); + else + { + switch (named_object->node.type) + { + case Node::Type::Buffer: + { + auto data = BAN::ConstByteSpan(named_object->node.as.str_buf->bytes, named_object->node.as.str_buf->size); + if (auto ret = Namespace::root_namespace().parse(data); ret.is_error()) + dwarnln("Failed to load {}: {}", named_object->node, ret.error()); + else + result.as.integer.value = BAN::numeric_limits::max(); + break; + } + default: + dwarnln("TODO: Load({}): {}", named_object_path, named_object->node); + return BAN::Error::from_errno(ENOTSUP); + } + } + + TRY(store_into_target(context, result)); + + return result; + } + + BAN::ErrorOr parse_timer_op(ParseContext& context) + { + dprintln_if(AML_DUMP_FUNCTION_CALLS, "parse_load_op"); + + 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::TimerOp); + context.aml_data = context.aml_data.slice(2); + + Node result; + result.type = Node::Type::Integer; + result.as.integer.value = SystemTimer::get().ns_since_boot() / 100; + return result; + } + + BAN::ErrorOr evaluate_node(const Scope& node_path, const Node& node) + { + switch (node.type) + { + case Node::Type::Uninitialized: + case Node::Type::Debug: + case Node::Type::OpRegion: + case Node::Type::Event: + case Node::Type::Device: + case Node::Type::Processor: + case Node::Type::PowerResource: + case Node::Type::ThermalZone: + case Node::Type::Mutex: + case Node::Type::PredefinedScope: + case Node::Type::Count: + break; + case Node::Type::Integer: + case Node::Type::String: + case Node::Type::Package: + case Node::Type::Buffer: + case Node::Type::Index: + case Node::Type::Reference: + return TRY(node.copy()); + case Node::Type::BufferField: + dwarnln("TODO: evaluate BufferField"); + return BAN::Error::from_errno(ENOTSUP); + case Node::Type::FieldUnit: + return convert_from_field_unit(node, ConvInteger | ConvBuffer, sizeof(uint64_t)); + case Node::Type::Method: + if (node.as.method.arg_count != 0) + return BAN::Error::from_errno(EFAULT); + return TRY(method_call(node_path, node, {})); + } + + dwarnln("evaluate {}", node); + return BAN::Error::from_errno(EINVAL); + } + + static BAN::ErrorOr method_call_impl(ParseContext& context) + { + dprintln_if(AML_DUMP_FUNCTION_CALLS, "method_call '{}'", context.scope); + + if (context.call_depth >= 128) + { + dwarnln("Terminating recursive method call"); + + Node return_value {}; + return_value.type = Node::Type::Integer; + return_value.as.integer.value = 0; + return return_value; + } + + TRY(context.allocate_locals()); + + Node return_value {}; + + context.call_depth++; + while (!context.aml_data.empty() && return_value.type == Node::Type::Uninitialized) + { + auto [execution_flow, node] = TRY(parse_node_or_execution_flow(context)); + + switch (execution_flow) + { + case ExecutionFlow::Normal: + break; + case ExecutionFlow::Break: + dwarnln("BreakOp in method"); + return BAN::Error::from_errno(EINVAL); + case ExecutionFlow::Continue: + dwarnln("ContinueOp in method"); + return BAN::Error::from_errno(EINVAL); + case ExecutionFlow::Return: + ASSERT(node.has_value()); + return_value = node.release_value(); + break; + } + } + context.call_depth--; + + while (!context.created_nodes.empty()) + { + TRY(Namespace::root_namespace().remove_named_object(context.created_nodes.back())); + context.created_nodes.pop_back(); + } + + // In the absence of an explicit Return () statement, the return value to the caller is undefined. + // We will just return 0 to keep things simple :) + if (return_value.type == Node::Type::Uninitialized) + { + return_value.type = Node::Type::Integer; + return_value.as.integer.value = 0; + } + + return return_value; + } + + BAN::ErrorOr method_call(const Scope& scope, const Node& method_node, BAN::Array&& args, uint32_t call_depth) + { + ASSERT(method_node.type == Node::Type::Method); + + size_t argc = 0; + for (argc = 0; argc < args.size(); argc++) + if (args[argc] == nullptr) + break; + for (size_t i = argc; i < args.size(); i++) + ASSERT(args[i] == nullptr); + + const auto& method = method_node.as.method; + + if (argc != method.arg_count) + { + dwarnln("{} takes {} arguments but {} were provided", scope, method.arg_count, argc); + return BAN::Error::from_errno(EINVAL); + } + + if (method.override_func) + return method.override_func(args); + + if (method.serialized) + { + ASSERT(method.mutex); + method.mutex->mutex.lock(); + } + + // FIXME: I'm pretty sure arguments are leaking memory + + ParseContext context; + context.scope = TRY(scope.copy()); + context.aml_data = BAN::ConstByteSpan(method.start, method.length); + context.call_depth = call_depth; + for (size_t i = 0; i < args.size(); i++) + context.args[i] = args[i]; + + auto result = method_call_impl(context); + if (method.serialized) + method.mutex->mutex.unlock(); + + return result; + } + + BAN::ErrorOr parse_node(ParseContext& context, bool return_ref) + { + if (context.aml_data.empty()) + return BAN::Error::from_errno(ENODATA); + + if (context.aml_data[0] == static_cast(AML::Byte::ExtOpPrefix)) { if (context.aml_data.size() < 2) - return ParseResult::Failure; + return BAN::Error::from_errno(ENODATA); - switch (static_cast(context.aml_data[1])) + const uint8_t opcode = context.aml_data[1]; + switch (static_cast(opcode)) { - case AML::ExtOp::FieldOp: - return AML::Field::parse(context); - case AML::ExtOp::IndexFieldOp: - return AML::IndexField::parse(context); - case AML::ExtOp::BankFieldOp: - return AML::BankField::parse(context); - case AML::ExtOp::CreateFieldOp: - return AML::BufferField::parse(context); - case AML::ExtOp::OpRegionOp: - 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: - return AML::Mutex::parse(context); - case AML::ExtOp::ProcessorOp: - return AML::Processor::parse(context); - case AML::ExtOp::PowerResOp: - return AML::PowerResource::parse(context); - case AML::ExtOp::ThermalZoneOp: - return AML::ThermalZone::parse(context); case AML::ExtOp::CondRefOfOp: - return AML::Reference::parse(context); - case AML::ExtOp::SleepOp: - return AML::Sleep::parse(context); + return TRY(parse_condrefof_op(context)); + case AML::ExtOp::AcquireOp: + return TRY(parse_acquire_op(context)); + case AML::ExtOp::LoadOp: + return TRY(parse_load_op(context)); + case AML::ExtOp::TimerOp: + return TRY(parse_timer_op(context)); + case AML::ExtOp::WaitOp: + return TRY(parse_wait_op(context)); case AML::ExtOp::DebugOp: + { context.aml_data = context.aml_data.slice(2); - return ParseResult(AML::Namespace::debug_node); + Node debug; + debug.type = Node::Type::Debug; + return BAN::move(debug); + } default: break; } - AML_TODO("{2H} {2H}", context.aml_data[0], context.aml_data[1]); - return ParseResult::Failure; + dwarnln("TODO: AML opcode {2H}e", opcode); + return BAN::Error::from_errno(ENOTSUP); } - switch (static_cast(context.aml_data[0])) + const uint8_t opcode = context.aml_data[0]; + switch (static_cast(opcode)) { case AML::Byte::ZeroOp: case AML::Byte::OneOp: @@ -102,21 +2598,62 @@ namespace Kernel::ACPI case AML::Byte::WordPrefix: case AML::Byte::DWordPrefix: case AML::Byte::QWordPrefix: - return AML::Integer::parse(context.aml_data); + return TRY(parse_integer(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(AML::Byte::Arg0); - context.aml_data = context.aml_data.slice(1); - return ParseResult(context.method_args[index]); - } + return TRY(parse_string(context.aml_data)); + case AML::Byte::BufferOp: + return TRY(parse_buffer_op(context)); + case AML::Byte::PackageOp: + case AML::Byte::VarPackageOp: + return TRY(parse_package_op(context)); + case AML::Byte::SizeOfOp: + return TRY(parse_sizeof_op(context)); + case AML::Byte::RefOfOp: + return TRY(parse_refof_op(context)); + case AML::Byte::DerefOfOp: + return TRY(parse_derefof_op(context)); + case AML::Byte::StoreOp: + return TRY(parse_store_op(context)); + case AML::Byte::CopyObjectOp: + return TRY(parse_copy_object_op(context)); + case AML::Byte::ConcatOp: + return TRY(parse_concat_op(context)); + case AML::Byte::MidOp: + return TRY(parse_mid_op(context)); + case AML::Byte::IndexOp: + return TRY(parse_index_op(context)); + case AML::Byte::ObjectTypeOp: + return TRY(parse_object_type_op(context)); + case AML::Byte::ToBufferOp: + case AML::Byte::ToDecimalStringOp: + case AML::Byte::ToHexStringOp: + case AML::Byte::ToIntegerOp: + return TRY(parse_explicit_conversion(context)); + case AML::Byte::IncrementOp: + case AML::Byte::DecrementOp: + return TRY(parse_inc_dec_op(context)); + case AML::Byte::NotOp: + return TRY(parse_unary_integer_op(context)); + case AML::Byte::AddOp: + case AML::Byte::SubtractOp: + case AML::Byte::MultiplyOp: + case AML::Byte::DivideOp: + case AML::Byte::ShiftLeftOp: + case AML::Byte::ShiftRightOp: + case AML::Byte::AndOp: + case AML::Byte::NandOp: + case AML::Byte::OrOp: + case AML::Byte::NorOp: + case AML::Byte::XorOp: + case AML::Byte::ModOp: + return TRY(parse_binary_integer_op(context)); + case AML::Byte::LAndOp: + case AML::Byte::LEqualOp: + case AML::Byte::LGreaterOp: + case AML::Byte::LLessOp: + case AML::Byte::LNotOp: + case AML::Byte::LOrOp: + return TRY(parse_logical_op(context)); case AML::Byte::Local0: case AML::Byte::Local1: case AML::Byte::Local2: @@ -126,154 +2663,641 @@ namespace Kernel::ACPI case AML::Byte::Local6: case AML::Byte::Local7: { - uint8_t index = context.aml_data[0] - static_cast(AML::Byte::Local0); + const uint8_t local_index = opcode - static_cast(AML::Byte::Local0); context.aml_data = context.aml_data.slice(1); - return ParseResult(context.method_locals[index]); + if (context.locals[local_index]->node.type == Node::Type::Uninitialized) + { + dwarnln("Trying to access uninitialized local"); + return BAN::Error::from_errno(EINVAL); + } + if (!return_ref) + return TRY(context.locals[local_index]->node.copy()); + Node reference; + reference.type = Node::Type::Reference; + reference.as.reference = context.locals[local_index]; + reference.as.reference->ref_count++; + return reference; } - 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::ToBufferOp: - case AML::Byte::ToHexStringOp: - case AML::Byte::ToIntegerOp: - case AML::Byte::ToStringOp: - return AML::Conversion::parse(context); - case AML::Byte::CreateBitFieldOp: - case AML::Byte::CreateByteFieldOp: - case AML::Byte::CreateWordFieldOp: - case AML::Byte::CreateDWordFieldOp: - case AML::Byte::CreateQWordFieldOp: - return AML::BufferField::parse(context); - case AML::Byte::ConcatOp: - return AML::Concat::parse(context); - case AML::Byte::AliasOp: - return AML::Alias::parse(context); - case AML::Byte::NameOp: - return AML::Name::parse(context); - case AML::Byte::PackageOp: - return AML::Package::parse(context); - case AML::Byte::MethodOp: - return AML::Method::parse(context); - case AML::Byte::BufferOp: - 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::BreakOp: - case AML::Byte::ContinueOp: - case AML::Byte::WhileOp: - return AML::While::parse(context); - case AML::Byte::StoreOp: - return AML::Store::parse(context); - case AML::Byte::CopyObjectOp: - return AML::CopyObject::parse(context); - case AML::Byte::DerefOfOp: - case AML::Byte::RefOfOp: - return AML::Reference::parse(context); - case AML::Byte::IndexOp: - return AML::Index::parse(context); - case AML::Byte::NotifyOp: - return AML::Notify::parse(context); - case AML::Byte::SizeOfOp: - return AML::SizeOf::parse(context); - case AML::Byte::ObjectTypeOp: - return AML::ObjectType::parse(context); - case AML::Byte::BreakPointOp: // TODO: support breakpoints? - case AML::Byte::NoopOp: - context.aml_data = context.aml_data.slice(1); - return ParseResult::Success; - case AML::Byte::ReturnOp: + 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: { + const uint8_t arg_index = opcode - static_cast(AML::Byte::Arg0); 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; + if (context.args[arg_index] == nullptr || context.args[arg_index]->node.type == Node::Type::Uninitialized) + { + dwarnln("Trying to access uninitialized arg"); + return BAN::Error::from_errno(EINVAL); + } + if (!return_ref) + return TRY(context.args[arg_index]->node.copy()); + Node reference; + reference.type = Node::Type::Reference; + reference.as.reference = context.args[arg_index]; + reference.as.reference->ref_count++; + return reference; } default: break; } - if (static_cast(context.aml_data[0]) == AML::Byte::RootChar - || static_cast(context.aml_data[0]) == AML::Byte::ParentPrefixChar - || static_cast(context.aml_data[0]) == AML::Byte::NullName - || is_lead_name_char(context.aml_data[0])) + if (!is_name_string_start(context.aml_data[0])) { - auto name_string = AML::NameString::parse(context.aml_data); - if (!name_string.has_value()) - return ParseResult::Failure; - auto aml_object = Namespace::root_namespace()->find_object(context.scope, name_string.value(), Namespace::FindMode::Normal); - if (!aml_object) - { - AML_ERROR("NameString {} not found in namespace", name_string.value()); - return ParseResult::Failure; - } - - auto underlying = aml_object->to_underlying(); - if (aml_object->type != AML::Node::Type::Method && underlying->type != AML::Node::Type::Method) - return ParseResult(aml_object); - - auto* method = static_cast( - aml_object->type == AML::Node::Type::Method - ? aml_object.ptr() - : underlying.ptr() - ); - - BAN::Array, 7> args; - for (uint8_t i = 0; i < method->arg_count; i++) - { - auto arg_result = AML::parse_object(context); - if (!arg_result.success() || !arg_result.node()) - { - AML_ERROR("Failed to parse argument {} for method {}", i, name_string.value()); - return ParseResult::Failure; - } - args[i] = arg_result.node(); - } - - auto result = method->invoke_with_sync_stack( - context.sync_stack, - args[0], - args[1], - args[2], - args[3], - args[4], - args[5], - args[6] - ); - if (!result.has_value()) - { - AML_ERROR("Failed to evaluate {}", name_string.value()); - return ParseResult::Failure; - } - if (!result.value()) - return ParseResult::Success; - return ParseResult(result.value()); + dwarnln("TODO: AML opcode {2H}", opcode); + return BAN::Error::from_errno(ENOTSUP); } - AML_TODO("{2H}", context.aml_data[0]); - return ParseResult::Failure; + auto name_string = TRY(parse_name_string(context.aml_data)); + + auto [object_scope, named_object] = TRY(Namespace::root_namespace().find_named_object(context.scope, name_string)); + if (named_object == nullptr) + { + dwarnln("could not find '{}'.'{}'", context.scope, name_string); + return BAN::Error::from_errno(ENOENT); + } + + if (named_object->node.type == Node::Type::Method) + { + BAN::Array args; + for (size_t i = 0; i < named_object->node.as.method.arg_count; i++) + { + auto temp = TRY(parse_node(context)); + if (temp.type == Node::Type::Reference) + { + args[i] = temp.as.reference; + args[i]->ref_count++; + } + else + { + args[i] = new Reference(); + if (args[i] == nullptr) + return BAN::Error::from_errno(ENOMEM); + args[i]->node = BAN::move(temp); + args[i]->ref_count = 1; + } + } + + return TRY(method_call(BAN::move(object_scope), named_object->node, BAN::move(args), context.call_depth)); + } + + if (!return_ref) + return TRY(named_object->node.copy()); + + Node reference; + reference.type = Node::Type::Reference; + reference.as.reference = named_object; + reference.as.reference->ref_count++; + return reference; + } + +// FIXME: WHY TF IS THIS USING ALMOST 2 KiB of stack +#pragma GCC diagnostic push +#if defined(__GNUC__) && !defined(__clang__) +#pragma GCC diagnostic ignored "-Wstack-usage=" +#endif + + BAN::ErrorOr parse_node_or_execution_flow(ParseContext& context) + { + if (context.aml_data.empty()) + return BAN::Error::from_errno(ENODATA); + + auto dummy_return = ExecutionFlowResult { + .elem1 = ExecutionFlow::Normal, + .elem2 = BAN::Optional(), + }; + + if (context.aml_data[0] == static_cast(AML::Byte::ExtOpPrefix)) + { + if (context.aml_data.size() < 2) + return BAN::Error::from_errno(ENODATA); + switch (static_cast(context.aml_data[1])) + { + case AML::ExtOp::MutexOp: + TRY(parse_mutex_op(context)); + return dummy_return; + case AML::ExtOp::FatalOp: + TRY(parse_fatal_op(context)); + return dummy_return; + case AML::ExtOp::EventOp: + TRY(parse_event_op(context)); + return dummy_return; + case AML::ExtOp::ResetOp: + case AML::ExtOp::SignalOp: + TRY(parse_reset_signal_op(context)); + return dummy_return; + case AML::ExtOp::CreateFieldOp: + TRY(parse_createfield_op(context)); + return dummy_return; + case AML::ExtOp::SleepOp: + TRY(parse_sleep_op(context)); + return dummy_return; + case AML::ExtOp::StallOp: + TRY(parse_stall_op(context)); + return dummy_return; + case AML::ExtOp::ReleaseOp: + TRY(parse_release_op(context)); + return dummy_return; + case AML::ExtOp::OpRegionOp: + TRY(parse_opregion_op(context)); + return dummy_return; + case AML::ExtOp::FieldOp: + TRY(parse_field_op(context)); + return dummy_return; + case AML::ExtOp::IndexFieldOp: + TRY(parse_index_field_op(context)); + return dummy_return; + case AML::ExtOp::BankFieldOp: + TRY(parse_bank_field_op(context)); + return dummy_return; + case AML::ExtOp::DeviceOp: + TRY(parse_device_op(context)); + return dummy_return; + case AML::ExtOp::ProcessorOp: + TRY(parse_processor_op(context)); + return dummy_return; + case AML::ExtOp::PowerResOp: + TRY(parse_power_resource_op(context)); + return dummy_return; + case AML::ExtOp::ThermalZoneOp: + TRY(parse_thermal_zone_op(context)); + return dummy_return; + default: + break; + } + } + + switch (static_cast(context.aml_data[0])) + { + case AML::Byte::AliasOp: + TRY(parse_alias_op(context)); + return dummy_return; + case AML::Byte::NameOp: + TRY(parse_name_op(context)); + return dummy_return; + case AML::Byte::MethodOp: + TRY(parse_method_op(context)); + return dummy_return; + case AML::Byte::NoopOp: + case AML::Byte::BreakPointOp: + context.aml_data = context.aml_data.slice(1); + return dummy_return; + case AML::Byte::ScopeOp: + TRY(parse_scope_op(context)); + return dummy_return; + case AML::Byte::NotifyOp: + TRY(parse_notify_op(context)); + return dummy_return; + case AML::Byte::CreateBitFieldOp: + case AML::Byte::CreateByteFieldOp: + case AML::Byte::CreateWordFieldOp: + case AML::Byte::CreateDWordFieldOp: + case AML::Byte::CreateQWordFieldOp: + TRY(parse_createfield_op(context)); + return dummy_return; + case AML::Byte::IfOp: + return parse_if_op(context); + case AML::Byte::WhileOp: + return parse_while_op(context); + case AML::Byte::BreakOp: + dprintln_if(AML_DUMP_FUNCTION_CALLS, "parse_break_op"); + context.aml_data = context.aml_data.slice(1); + return ExecutionFlowResult { + .elem1 = ExecutionFlow::Break, + .elem2 = BAN::Optional(), + }; + case AML::Byte::ContinueOp: + dprintln_if(AML_DUMP_FUNCTION_CALLS, "parse_continue_op"); + context.aml_data = context.aml_data.slice(1); + return ExecutionFlowResult { + .elem1 = ExecutionFlow::Continue, + .elem2 = BAN::Optional(), + }; + case AML::Byte::ReturnOp: + { + dprintln_if(AML_DUMP_FUNCTION_CALLS, "parse_return_op"); + context.aml_data = context.aml_data.slice(1); + return ExecutionFlowResult { + .elem1 = ExecutionFlow::Return, + .elem2 = TRY(parse_node(context)), + }; + } + default: + break; + } + + auto node = TRY(parse_node(context)); + return ExecutionFlowResult { + .elem1 = ExecutionFlow::Normal, + .elem2 = BAN::move(node) + }; + } + +#pragma GCC diagnostic pop + + BAN::ErrorOr NameString::from_string(BAN::StringView name) + { + NameString result; + + if (name.front() == '\\') + { + result.base = base_root; + name = name.substring(1); + } + else + { + for (size_t i = 0; i < name.size() && name[i] == '^'; i++) + result.base++; + name = name.substring(result.base); + } + + ASSERT((name.size() % 4) == 0); + TRY(result.parts.reserve(name.size() / 4)); + + while (!name.empty()) + { + const uint32_t name_seg { + (static_cast(name[0]) << 0) | + (static_cast(name[1]) << 8) | + (static_cast(name[2]) << 16) | + (static_cast(name[3]) << 24) + }; + TRY(result.parts.push_back(name_seg)); + name = name.substring(4); + } + + return result; + } + + ParseContext::~ParseContext() + { + for (auto*& local : locals) + { + if (local && --local->ref_count == 0) + delete local; + local = nullptr; + } + for (auto*& arg : args) + { + if (arg && --arg->ref_count == 0) + delete arg; + arg = nullptr; + } + } + + BAN::ErrorOr ParseContext::allocate_locals() + { + for (auto*& local : locals) + { + ASSERT(local == nullptr); + local = new Reference(); + if (local == nullptr) + return BAN::Error::from_errno(ENOMEM); + local->ref_count = 1; + } + + return {}; + } + + BAN::ErrorOr Node::copy() const + { + Node result {}; + result.type = this->type; + + switch (this->type) + { + case Type::Uninitialized: + break; + case Type::Debug: + break; + case Type::Integer: + result.as.integer.value = this->as.integer.value; + break; + case Type::String: + case Type::Buffer: + ASSERT(this->as.str_buf); + result.as.str_buf = static_cast(kmalloc(sizeof(Buffer) + this->as.str_buf->size)); + if (result.as.str_buf == nullptr) + return BAN::Error::from_errno(ENOMEM); + memcpy(result.as.str_buf->bytes, this->as.str_buf->bytes, this->as.str_buf->size); + result.as.str_buf->size = this->as.str_buf->size; + result.as.str_buf->ref_count = 1; + break; + case Type::Package: + ASSERT(this->as.package); + result.as.package = static_cast(kmalloc(sizeof(Package) + this->as.package->num_elements * sizeof(Package::Element))); + if (result.as.package == nullptr) + return BAN::Error::from_errno(ENOMEM); + result.as.package->num_elements = this->as.package->num_elements; + result.as.package->ref_count = 1; + for (size_t i = 0; i < result.as.package->num_elements; i++) + { + auto& dst_elem = result.as.package->elements[i]; + const auto& src_elem = this->as.package->elements[i]; + + if (src_elem.resolved) + { + dst_elem.resolved = true; + dst_elem.value.node = nullptr; + if (src_elem.value.node) + { + dst_elem.value.node = new Node(); + if (dst_elem.value.node == nullptr) + return BAN::Error::from_errno(ENOMEM); + *dst_elem.value.node = TRY(src_elem.value.node->copy()); + } + } + else + { + dst_elem.resolved = false; + dst_elem.value.location = nullptr; + if (src_elem.value.location) + { + dst_elem.value.location = new Package::Element::Location(); + if (dst_elem.value.location == nullptr) + return BAN::Error::from_errno(ENOMEM); + dst_elem.value.location->name = TRY(src_elem.value.location->name.copy()); + dst_elem.value.location->scope = TRY(src_elem.value.location->scope.copy()); + } + } + } + break; + case Type::BufferField: + result.as.buffer_field = this->as.buffer_field; + result.as.buffer_field.buffer->ref_count++; + break; + case Type::OpRegion: + result.as.opregion = this->as.opregion; + break; + case Type::FieldUnit: + result.as.field_unit = this->as.field_unit; + switch (result.as.field_unit.type) + { + case FieldUnit::Type::Field: + break; + case FieldUnit::Type::IndexField: + result.as.field_unit.as.index_field.index->ref_count++; + result.as.field_unit.as.index_field.data->ref_count++; + break; + case FieldUnit::Type::BankField: + result.as.field_unit.as.bank_field.bank_selector->ref_count++; + break; + default: + ASSERT_NOT_REACHED(); + } + break; + case Type::Method: + result.as.method = this->as.method; + if (result.as.method.mutex) + result.as.method.mutex->ref_count++; + break; + case Type::Index: + switch (this->as.index.type) + { + case Node::Type::String: + case Node::Type::Buffer: + ASSERT(this->as.index.as.str_buf); + result.as.index.as.str_buf = this->as.index.as.str_buf; + result.as.index.as.str_buf->ref_count++; + break; + case Node::Type::Package: + ASSERT(this->as.index.as.package); + result.as.index.as.package = this->as.index.as.package; + result.as.index.as.package->ref_count++; + break; + default: ASSERT_NOT_REACHED(); + } + result.as.index.type = this->as.index.type; + result.as.index.index = this->as.index.index; + break; + case Type::Reference: + ASSERT(this->as.reference); + result.as.reference = this->as.reference; + result.as.reference->ref_count++; + break; + case Type::Event: + dwarnln("Copy Event"); + return BAN::Error::from_errno(EINVAL); + case Type::Device: + dwarnln("Copy Device"); + return BAN::Error::from_errno(EINVAL); + case Type::Processor: + dwarnln("Copy Processor"); + return BAN::Error::from_errno(EINVAL); + case Type::PowerResource: + dwarnln("Copy PowerResource"); + return BAN::Error::from_errno(EINVAL); + case Type::ThermalZone: + dwarnln("Copy ThremalZone"); + return BAN::Error::from_errno(EINVAL); + case Type::Mutex: + dwarnln("Copy Mutex"); + return BAN::Error::from_errno(EINVAL); + case Type::PredefinedScope: + dwarnln("Copy Scope"); + return BAN::Error::from_errno(EINVAL); + case Type::Count: + ASSERT_NOT_REACHED(); + } + + return result; + } + + Node& Node::operator=(Node&& other) + { + clear(); + + switch (other.type) + { + case Type::Uninitialized: + break; + case Type::Debug: + break; + case Type::Integer: + this->as.integer = other.as.integer; + other.as.integer = {}; + break; + case Type::String: + case Type::Buffer: + this->as.str_buf = other.as.str_buf; + other.as.str_buf = {}; + break; + case Type::Package: + this->as.package = other.as.package; + other.as.package = {}; + break; + case Type::BufferField: + this->as.buffer_field = other.as.buffer_field; + other.as.buffer_field = {}; + break; + case Type::OpRegion: + this->as.opregion = other.as.opregion; + other.as.opregion = {}; + break; + case Type::FieldUnit: + this->as.field_unit = other.as.field_unit; + other.as.field_unit = {}; + break; + case Type::Event: + break; + case Type::Device: + break; + case Type::Processor: + break; + case Type::PowerResource: + break; + case Type::ThermalZone: + break; + case Type::Method: + this->as.method = other.as.method; + other.as.method = {}; + break; + case Type::Mutex: + this->as.mutex = other.as.mutex; + other.as.mutex = {}; + break; + case Type::Index: + this->as.index = other.as.index; + other.as.index = {}; + break; + case Type::Reference: + this->as.reference = other.as.reference; + other.as.reference = {}; + break; + case Type::PredefinedScope: + break; + case Type::Count: + ASSERT_NOT_REACHED(); + } + this->type = other.type; + other.type = Node::Type::Uninitialized; + + return *this; + } + + static void deref_package(Package* package) + { + if (package == nullptr || --package->ref_count != 0) + return; + for (size_t i = 0; i < package->num_elements; i++) + { + auto& elem = package->elements[i]; + + if (elem.resolved) + { + if (elem.value.node) + delete elem.value.node; + elem.value.node = nullptr; + } + else + { + if (elem.value.location) + delete elem.value.location; + elem.value.location = nullptr; + } + } + kfree(package); + } + + void Node::clear() + { + switch (this->type) + { + case Type::Uninitialized: + break; + case Type::Debug: + break; + case Type::Integer: + break; + case Type::String: + case Type::Buffer: + if (this->as.str_buf && --this->as.str_buf->ref_count == 0) + kfree(this->as.str_buf); + this->as.str_buf = {}; + break; + case Type::Package: + deref_package(this->as.package); + this->as.package = {}; + break; + case Type::BufferField: + if (this->as.buffer_field.buffer && --this->as.buffer_field.buffer->ref_count == 0) + delete this->as.buffer_field.buffer; + this->as.buffer_field = {}; + break; + case Type::OpRegion: + this->as.opregion = {}; + break; + case Type::FieldUnit: + switch (this->as.field_unit.type) + { + case FieldUnit::Type::Field: + break; + case FieldUnit::Type::IndexField: + if (--this->as.field_unit.as.index_field.index->ref_count == 0) + delete this->as.field_unit.as.index_field.index; + if (--this->as.field_unit.as.index_field.data->ref_count == 0) + delete this->as.field_unit.as.index_field.data; + break; + case FieldUnit::Type::BankField: + if (--this->as.field_unit.as.bank_field.bank_selector->ref_count == 0) + delete this->as.field_unit.as.bank_field.bank_selector; + break; + default: + ASSERT_NOT_REACHED(); + } + this->as.field_unit = {}; + break; + case Type::Event: + break; + case Type::Device: + break; + case Type::Processor: + break; + case Type::PowerResource: + break; + case Type::ThermalZone: + break; + case Type::Method: + if (this->as.method.mutex && --this->as.method.mutex->ref_count == 0) + delete this->as.method.mutex; + this->as.method = {}; + break; + case Type::Mutex: + if (this->as.mutex && --this->as.mutex->ref_count == 0) + delete this->as.mutex; + this->as.mutex = {}; + break; + case Type::Index: + switch (this->as.index.type) + { + case Type::Uninitialized: + break; + case Type::String: + case Type::Buffer: + if (this->as.index.as.str_buf && --this->as.index.as.str_buf->ref_count == 0) + kfree(this->as.index.as.str_buf); + break; + case Type::Package: + deref_package(this->as.index.as.package); + break; + default: ASSERT_NOT_REACHED(); + } + this->as.index = {}; + break; + case Type::Reference: + if (this->as.reference && --this->as.reference->ref_count == 0) + delete this->as.reference; + this->as.reference = {}; + break; + case Type::PredefinedScope: + break; + case Type::Count: + ASSERT_NOT_REACHED(); + } + this->type = Type::Uninitialized; } } diff --git a/kernel/kernel/ACPI/AML/OpRegion.cpp b/kernel/kernel/ACPI/AML/OpRegion.cpp new file mode 100644 index 00000000..143e2e8f --- /dev/null +++ b/kernel/kernel/ACPI/AML/OpRegion.cpp @@ -0,0 +1,806 @@ +#include +#include +#include +#include +#include +#include + +namespace Kernel::ACPI::AML +{ + + static BAN::ErrorOr parse_pkg_length(BAN::ConstByteSpan& aml_data) + { + if (aml_data.empty()) + return BAN::Error::from_errno(ENODATA); + + const uint32_t encoding_length = (aml_data[0] >> 6) + 1; + if (aml_data.size() < encoding_length) + return BAN::Error::from_errno(ENODATA); + + uint32_t pkg_length = 0; + switch (encoding_length) + { + case 1: + pkg_length |= aml_data[0] & 0x3F; + break; + case 2: + pkg_length |= aml_data[0] & 0x0F; + pkg_length |= aml_data[1] << 4; + break; + case 3: + pkg_length |= aml_data[0] & 0x0F; + pkg_length |= aml_data[1] << 4; + pkg_length |= aml_data[2] << 12; + break; + case 4: + pkg_length |= aml_data[0] & 0x0F; + pkg_length |= aml_data[1] << 4; + pkg_length |= aml_data[2] << 12; + pkg_length |= aml_data[3] << 20; + break; + } + + aml_data = aml_data.slice(encoding_length); + return pkg_length; + } + + BAN::ErrorOr parse_opregion_op(ParseContext& context) + { + dprintln_if(AML_DUMP_FUNCTION_CALLS, "parse_opregion_op"); + + 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::OpRegionOp); + context.aml_data = context.aml_data.slice(2); + + auto region_name = TRY(parse_name_string(context.aml_data)); + + if (context.aml_data.empty()) + return BAN::Error::from_errno(ENODATA); + auto region_space = context.aml_data[0]; + context.aml_data = context.aml_data.slice(1); + + switch (static_cast(region_space)) + { + case GAS::AddressSpaceID::SystemMemory: + case GAS::AddressSpaceID::SystemIO: + case GAS::AddressSpaceID::PCIConfig: + case GAS::AddressSpaceID::EmbeddedController: + case GAS::AddressSpaceID::SMBus: + case GAS::AddressSpaceID::SystemCMOS: + case GAS::AddressSpaceID::PCIBarTarget: + case GAS::AddressSpaceID::IPMI: + case GAS::AddressSpaceID::GeneralPurposeIO: + case GAS::AddressSpaceID::GenericSerialBus: + case GAS::AddressSpaceID::PlatformCommunicationChannel: + break; + default: + if (region_space < 0x80) + { + dwarnln("OpRegion invalid region space {2H}", region_space); + return BAN::Error::from_errno(EINVAL); + } + break; + } + + auto region_offset = TRY(convert_node(TRY(parse_node(context)), ConvInteger, sizeof(uint64_t))); + auto region_length = TRY(convert_node(TRY(parse_node(context)), ConvInteger, sizeof(uint64_t))); + + Node opregion; + opregion.type = Node::Type::OpRegion; + opregion.as.opregion.address_space = static_cast(region_space); + opregion.as.opregion.offset = region_offset.as.integer.value; + opregion.as.opregion.length = region_length.as.integer.value; + + TRY(Namespace::root_namespace().add_named_object(context.scope, region_name, BAN::move(opregion))); + + return {}; + } + + template + static BAN::ErrorOr parse_field_list(const Scope& scope, BAN::ConstByteSpan field_list_pkg, const F& create_element, uint8_t field_flags) + { + uint64_t offset = 0; + while (!field_list_pkg.empty()) + { + switch (field_list_pkg[0]) + { + case 0x00: + field_list_pkg = field_list_pkg.slice(1); + offset += TRY(parse_pkg_length(field_list_pkg)); + break; + case 0x01: + // FIXME: do something with + if (field_list_pkg.size() < 3) + return BAN::Error::from_errno(ENODATA); + field_flags &= 0xF0; + field_flags |= field_list_pkg[1] & 0x0F; + field_list_pkg = field_list_pkg.slice(3); + break; + case 0x02: + dwarnln("TODO: connect field"); + return BAN::Error::from_errno(ENOTSUP); + case 0x03: + dwarnln("TODO: extended access field"); + return BAN::Error::from_errno(ENOTSUP); + default: + { + if (field_list_pkg.size() < 4) + return BAN::Error::from_errno(ENODATA); + if (!is_lead_name_char(field_list_pkg[0]) || !is_name_char(field_list_pkg[1]) || !is_name_char(field_list_pkg[2]) || !is_name_char(field_list_pkg[3])) + { + dwarnln("Invalid NameSeg {2H}, {2H}, {2H}, {2H}", + field_list_pkg[0], field_list_pkg[1], field_list_pkg[2], field_list_pkg[3] + ); + return BAN::Error::from_errno(EINVAL); + } + const uint32_t name_seg = field_list_pkg.as(); + field_list_pkg = field_list_pkg.slice(4); + const auto field_length = TRY(parse_pkg_length(field_list_pkg)); + + NameString field_name; + field_name.base = 0; + TRY(field_name.parts.push_back(name_seg)); + + Node field_node = create_element(offset, field_length, field_flags); + + TRY(Namespace::root_namespace().add_named_object(scope, field_name, BAN::move(field_node))); + + offset += field_length; + + break; + } + } + } + + return {}; + } + + BAN::ErrorOr parse_field_op(ParseContext& context) + { + dprintln_if(AML_DUMP_FUNCTION_CALLS, "parse_field_op"); + + 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::FieldOp); + context.aml_data = context.aml_data.slice(2); + + auto field_pkg = TRY(parse_pkg(context.aml_data)); + auto opregion_name = TRY(parse_name_string(field_pkg)); + if (field_pkg.empty()) + return BAN::Error::from_errno(ENODATA); + auto default_flags = field_pkg[0]; + field_pkg = field_pkg.slice(1); + + auto [_, opregion] = TRY(Namespace::root_namespace().find_named_object(context.scope, opregion_name)); + if (opregion == nullptr) + { + dwarnln("could not find '{}'.'{}'", context.scope, opregion_name); + return BAN::Error::from_errno(ENOENT); + } + if (opregion->node.type != Node::Type::OpRegion) + { + dwarnln("Field source is {}", opregion->node); + return BAN::Error::from_errno(EINVAL); + } + + const auto create_element = + [&](uint64_t offset, uint64_t length, uint8_t field_flags) -> Node + { + Node field_node {}; + field_node.type = Node::Type::FieldUnit; + field_node.as.field_unit.type = FieldUnit::Type::Field; + field_node.as.field_unit.as.field.opregion = opregion->node.as.opregion; + field_node.as.field_unit.length = length; + field_node.as.field_unit.offset = offset; + field_node.as.field_unit.flags = field_flags; + return field_node; + }; + + TRY(parse_field_list(context.scope, field_pkg, create_element, default_flags)); + + return {}; + } + + BAN::ErrorOr parse_index_field_op(ParseContext& context) + { + dprintln_if(AML_DUMP_FUNCTION_CALLS, "parse_index_field_op"); + + 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::IndexFieldOp); + context.aml_data = context.aml_data.slice(2); + + auto field_pkg = TRY(parse_pkg(context.aml_data)); + + auto index_name = TRY(parse_name_string(field_pkg)); + auto data_name = TRY(parse_name_string(field_pkg)); + if (field_pkg.empty()) + return BAN::Error::from_errno(ENODATA); + auto default_flags = field_pkg[0]; + field_pkg = field_pkg.slice(1); + + auto [_1, index_obj] = TRY(Namespace::root_namespace().find_named_object(context.scope, index_name)); + if (index_obj == nullptr) + { + dwarnln("could not find '{}'.'{}'", context.scope, index_name); + return BAN::Error::from_errno(ENOENT); + } + if (index_obj->node.type != Node::Type::FieldUnit) + { + dwarnln("IndexField source is {}", index_obj->node); + return BAN::Error::from_errno(EINVAL); + } + + auto [_2, data_obj] = TRY(Namespace::root_namespace().find_named_object(context.scope, data_name)); + if (data_obj == nullptr) + { + dwarnln("could not find '{}'.'{}'", context.scope, data_name); + return BAN::Error::from_errno(ENOENT); + } + if (data_obj->node.type != Node::Type::FieldUnit) + { + dwarnln("IndexField source is {}", data_obj->node); + return BAN::Error::from_errno(EINVAL); + } + + const auto create_element = + [&](uint64_t offset, uint64_t length, uint8_t field_flags) -> Node + { + Node field_node {}; + field_node.type = Node::Type::FieldUnit; + field_node.as.field_unit.type = FieldUnit::Type::IndexField; + field_node.as.field_unit.as.index_field.index = index_obj; + field_node.as.field_unit.as.index_field.index->ref_count++; + field_node.as.field_unit.as.index_field.data = data_obj; + field_node.as.field_unit.as.index_field.data->ref_count++; + field_node.as.field_unit.length = length; + field_node.as.field_unit.offset = offset; + field_node.as.field_unit.flags = field_flags; + return field_node; + }; + + TRY(parse_field_list(context.scope, field_pkg, create_element, default_flags)); + + return {}; + } + + BAN::ErrorOr parse_bank_field_op(ParseContext& context) + { + dprintln_if(AML_DUMP_FUNCTION_CALLS, "parse_bank_field_op"); + + 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::BankFieldOp); + context.aml_data = context.aml_data.slice(2); + + auto field_pkg = TRY(parse_pkg(context.aml_data)); + auto opregion_name = TRY(parse_name_string(field_pkg)); + auto bank_selector_name = TRY(parse_name_string(field_pkg)); + + auto temp_aml_data = context.aml_data; + context.aml_data = field_pkg; + auto bank_value_node = TRY(parse_node(context)); + field_pkg = context.aml_data; + context.aml_data = temp_aml_data; + + if (field_pkg.empty()) + return BAN::Error::from_errno(ENODATA); + auto default_flags = field_pkg[0]; + field_pkg = field_pkg.slice(1); + + auto [_1, opregion] = TRY(Namespace::root_namespace().find_named_object(context.scope, opregion_name)); + if (opregion == nullptr) + { + dwarnln("could not find '{}'.'{}'", context.scope, opregion_name); + return BAN::Error::from_errno(ENOENT); + } + if (opregion->node.type != Node::Type::OpRegion) + { + dwarnln("Field source is {}", opregion->node); + return BAN::Error::from_errno(EINVAL); + } + + auto [_2, bank_selector] = TRY(Namespace::root_namespace().find_named_object(context.scope, bank_selector_name)); + if (bank_selector == nullptr) + { + dwarnln("could not find '{}'.'{}'", context.scope, bank_selector_name); + return BAN::Error::from_errno(ENOENT); + } + if (bank_selector->node.type != Node::Type::FieldUnit) + { + dwarnln("BankField bank selector is {}", bank_selector->node); + return BAN::Error::from_errno(EINVAL); + } + + const uint64_t bank_value = TRY(convert_node(BAN::move(bank_value_node), ConvInteger, sizeof(uint64_t))).as.integer.value; + + const auto create_element = + [&](uint64_t offset, uint64_t length, uint8_t field_flags) -> Node + { + Node field_node {}; + field_node.type = Node::Type::FieldUnit; + field_node.as.field_unit.type = FieldUnit::Type::BankField; + field_node.as.field_unit.as.bank_field.opregion = opregion->node.as.opregion; + field_node.as.field_unit.as.bank_field.bank_selector = bank_selector; + field_node.as.field_unit.as.bank_field.bank_selector->ref_count++; + field_node.as.field_unit.as.bank_field.bank_value = bank_value; + field_node.as.field_unit.length = length; + field_node.as.field_unit.offset = offset; + field_node.as.field_unit.flags = field_flags; + return field_node; + }; + + TRY(parse_field_list(context.scope, field_pkg, create_element, default_flags)); + + return {}; + } + + struct AccessRule + { + uint8_t access_bits; + bool lock; + enum { + Preserve, + WriteZeros, + WriteOnes, + } update_rule; + }; + + static AccessRule parse_access_rule(uint8_t flags) + { + AccessRule rule; + + switch (flags & 0x0F) + { + case 0: rule.access_bits = 8; break; + case 1: rule.access_bits = 8; break; + case 2: rule.access_bits = 16; break; + case 3: rule.access_bits = 32; break; + case 4: rule.access_bits = 64; break; + case 5: rule.access_bits = 8; break; + default: ASSERT_NOT_REACHED(); + } + + rule.lock = !!(flags & 0x10); + + switch ((flags >> 5) & 0x03) + { + case 0: rule.update_rule = AccessRule::Preserve; break; + case 1: rule.update_rule = AccessRule::WriteOnes; break; + case 2: rule.update_rule = AccessRule::WriteZeros; break; + default: ASSERT_NOT_REACHED(); + } + + return rule; + } + + static BAN::ErrorOr perform_opregion_read(const OpRegion& opregion, uint8_t access_size, uint64_t offset) + { + ASSERT(offset % access_size == 0); + + const uint64_t byte_offset = opregion.offset + offset; + + switch (opregion.address_space) + { + case GAS::AddressSpaceID::SystemMemory: + { + uint64_t result; + PageTable::with_fast_page(byte_offset & PAGE_ADDR_MASK, [&]() { + void* addr = PageTable::fast_page_as_ptr(byte_offset % PAGE_SIZE); + switch (access_size) { + case 1: result = *static_cast(addr); break; + case 2: result = *static_cast(addr); break; + case 4: result = *static_cast(addr); break; + case 8: result = *static_cast(addr); break; + default: ASSERT_NOT_REACHED(); + } + }); + return result; + } + case GAS::AddressSpaceID::SystemIO: + if (byte_offset + access_size > 0x10000) + { + dwarnln("{} byte read from IO port 0x{H}", access_size, byte_offset); + return BAN::Error::from_errno(EINVAL); + } + switch (access_size) + { + case 1: return IO::inb(byte_offset); + case 2: return IO::inw(byte_offset); + case 4: return IO::inl(byte_offset); + default: + dwarnln("{} byte read from IO port", access_size); + return BAN::Error::from_errno(EINVAL); + } + ASSERT_NOT_REACHED(); + case GAS::AddressSpaceID::PCIConfig: + { + // https://uefi.org/htmlspecs/ACPI_Spec_6_4_html/05_ACPI_Software_Programming_Model/ACPI_Software_Programming_Model.html#address-space-format + // PCI configuration space is confined to segment 0, bus 0 + + const uint16_t device = (byte_offset >> 32) & 0xFFFF; + const uint16_t function = (byte_offset >> 16) & 0xFFFF; + const uint16_t offset = byte_offset & 0xFFFF; + switch (access_size) + { + case 1: return PCI::PCIManager::get().read_config_byte (0, device, function, offset); + case 2: return PCI::PCIManager::get().read_config_word (0, device, function, offset); + case 4: return PCI::PCIManager::get().read_config_dword(0, device, function, offset); + default: + dwarnln("{} byte read from PCI {2H}:{2H}:{2H}", device, function, offset); + return BAN::Error::from_errno(EINVAL); + } + ASSERT_NOT_REACHED(); + } + case GAS::AddressSpaceID::EmbeddedController: + case GAS::AddressSpaceID::SMBus: + case GAS::AddressSpaceID::SystemCMOS: + case GAS::AddressSpaceID::PCIBarTarget: + case GAS::AddressSpaceID::IPMI: + case GAS::AddressSpaceID::GeneralPurposeIO: + case GAS::AddressSpaceID::GenericSerialBus: + case GAS::AddressSpaceID::PlatformCommunicationChannel: + dwarnln("TODO: Read from address space {}", static_cast(opregion.address_space)); + return BAN::Error::from_errno(ENOTSUP); + } + + ASSERT_NOT_REACHED(); + } + + static BAN::ErrorOr perform_opregion_write(const OpRegion& opregion, uint8_t access_size, uint64_t offset, uint64_t value) + { + ASSERT(offset % access_size == 0); + + const uint64_t byte_offset = opregion.offset + offset; + + switch (opregion.address_space) + { + case GAS::AddressSpaceID::SystemMemory: + PageTable::with_fast_page(byte_offset & PAGE_ADDR_MASK, [&]() { + void* addr = PageTable::fast_page_as_ptr(byte_offset % PAGE_SIZE); + switch (access_size) { + case 1: *static_cast(addr) = value; break; + case 2: *static_cast(addr) = value; break; + case 4: *static_cast(addr) = value; break; + case 8: *static_cast(addr) = value; break; + default: ASSERT_NOT_REACHED(); + } + }); + return {}; + case GAS::AddressSpaceID::SystemIO: + if (byte_offset + access_size > 0x10000) + { + dwarnln("{} byte write to IO port 0x{H}", access_size, byte_offset); + return BAN::Error::from_errno(EINVAL); + } + switch (access_size) + { + case 1: IO::outb(byte_offset, value); break; + case 2: IO::outw(byte_offset, value); break; + case 4: IO::outl(byte_offset, value); break; + default: + dwarnln("{} byte write to IO port", access_size); + return BAN::Error::from_errno(EINVAL); + } + return {}; + case GAS::AddressSpaceID::PCIConfig: + { + // https://uefi.org/htmlspecs/ACPI_Spec_6_4_html/05_ACPI_Software_Programming_Model/ACPI_Software_Programming_Model.html#address-space-format + // PCI configuration space is confined to segment 0, bus 0 + + const uint16_t device = (byte_offset >> 32) & 0xFFFF; + const uint16_t function = (byte_offset >> 16) & 0xFFFF; + const uint16_t offset = byte_offset & 0xFFFF; + switch (access_size) + { + case 1: PCI::PCIManager::get().write_config_byte (0, device, function, offset, value); break; + case 2: PCI::PCIManager::get().write_config_word (0, device, function, offset, value); break; + case 4: PCI::PCIManager::get().write_config_dword(0, device, function, offset, value); break; + default: + dwarnln("{} byte write to PCI {2H}:{2H}:{2H}", device, function, offset); + return BAN::Error::from_errno(EINVAL); + } + return {}; + } + case GAS::AddressSpaceID::EmbeddedController: + case GAS::AddressSpaceID::SMBus: + case GAS::AddressSpaceID::SystemCMOS: + case GAS::AddressSpaceID::PCIBarTarget: + case GAS::AddressSpaceID::IPMI: + case GAS::AddressSpaceID::GeneralPurposeIO: + case GAS::AddressSpaceID::GenericSerialBus: + case GAS::AddressSpaceID::PlatformCommunicationChannel: + dwarnln("TODO: Write to address space {}", static_cast(opregion.address_space)); + return BAN::Error::from_errno(ENOTSUP); + } + + ASSERT_NOT_REACHED(); + } + + struct BufferInfo + { + const uint8_t* buffer; + const uint64_t bytes; + }; + + static BAN::ErrorOr extract_buffer_info(const Node& source) + { + switch (source.type) + { + case Node::Type::String: + case Node::Type::Buffer: + return BufferInfo { + .buffer = source.as.str_buf->bytes, + .bytes = source.as.str_buf->size, + }; + case Node::Type::Integer: + return BufferInfo { + .buffer = reinterpret_cast(&source.as.integer.value), + .bytes = sizeof(uint64_t), + }; + default: + dwarnln("Invalid store of {} to FieldUnit", source); + return BAN::Error::from_errno(EINVAL); + } + + ASSERT_NOT_REACHED(); + } + + static BAN::ErrorOr allocate_destination(const Node& source, Node::Type type, size_t max_bytes) + { + ASSERT(source.type == Node::Type::FieldUnit); + + const uint64_t source_bit_length = source.as.field_unit.length; + + Node result; + result.type = type; + + switch (type) + { + case Node::Type::Buffer: + { + const size_t dst_bits = BAN::Math::max(max_bytes * 8, source_bit_length); + const size_t bytes = BAN::Math::div_round_up(dst_bits, 8); + + result.as.str_buf = static_cast(kmalloc(sizeof(Buffer) + bytes)); + if (result.as.str_buf == nullptr) + return BAN::Error::from_errno(ENOMEM); + result.as.str_buf->size = bytes; + result.as.str_buf->ref_count = 1; + memset(result.as.str_buf->bytes, 0, bytes); + + break; + } + case Node::Type::Integer: + if (source_bit_length > 64) + { + dwarnln("Convert field unit of {} bits to an integer", source_bit_length); + return BAN::Error::from_errno(EINVAL); + } + + result.as.integer.value = 0; + + break; + default: + ASSERT_NOT_REACHED(); + } + + return result; + } + + static void write_bits_to_buffer(uint8_t* buffer, size_t bit_offset, uint64_t value, size_t bit_count) + { + size_t bits_done = 0; + while (bits_done < bit_count) { + const size_t acc_bit_offset = (bit_offset + bits_done) % 8; + const size_t acc_size = BAN::Math::min(bit_count - bits_done, 8 - acc_bit_offset); + const size_t mask = (1 << acc_size) - 1; + + buffer[(bit_offset + bits_done) / 8] |= ((value >> bits_done) & mask) << acc_bit_offset; + + bits_done += acc_size; + } + } + + static uint64_t read_bits_from_buffer(const uint8_t* buffer, size_t bit_offset, size_t bit_count) + { + uint64_t result = 0; + + size_t bits_done = 0; + while (bits_done < bit_count) { + const size_t acc_bit_offset = (bit_offset + bits_done) % 8; + const size_t acc_size = BAN::Math::min(bit_count - bits_done, 8 - acc_bit_offset); + const size_t mask = (1 << acc_size) - 1; + + result |= static_cast((buffer[(bit_offset + bits_done) / 8] >> acc_bit_offset) & mask) << bits_done; + + bits_done += acc_size; + } + + return result; + } + + static BAN::ErrorOr perform_index_field_read(const Node& source, uint64_t acc_byte_offset) + { + ASSERT(source.type == Node::Type::FieldUnit); + ASSERT(source.as.field_unit.type == FieldUnit::Type::IndexField); + + Node index_node; + index_node.type = Node::Type::Integer; + index_node.as.integer.value = acc_byte_offset; + TRY(store_to_field_unit(index_node, source.as.field_unit.as.index_field.index->node)); + + auto value = TRY(convert_from_field_unit(source.as.field_unit.as.index_field.data->node, ConvInteger, sizeof(uint64_t))); + return value.as.integer.value; + } + + static BAN::ErrorOr perform_index_field_write(const Node& source, uint64_t acc_byte_offset, uint64_t value) + { + ASSERT(source.type == Node::Type::FieldUnit); + ASSERT(source.as.field_unit.type == FieldUnit::Type::IndexField); + + Node index_node; + index_node.type = Node::Type::Integer; + index_node.as.integer.value = acc_byte_offset; + TRY(store_to_field_unit(index_node, source.as.field_unit.as.index_field.index->node)); + + Node data_node; + data_node.type = Node::Type::Integer; + data_node.as.integer.value = value; + TRY(store_to_field_unit(data_node, source.as.field_unit.as.index_field.data->node)); + return {}; + } + + BAN::ErrorOr convert_from_field_unit(const Node& source, uint8_t conversion, size_t max_length) + { + ASSERT(source.type == Node::Type::FieldUnit); + + const bool can_be_integer = source.as.field_unit.length <= 64; + + auto target_type = Node::Type::Uninitialized; + if (can_be_integer && (conversion & Conversion::ConvInteger)) + target_type = Node::Type::Integer; + else if (conversion & Conversion::ConvBuffer) + target_type = Node::Type::Buffer; + + if (target_type == Node::Type::Uninitialized) + { + dwarnln("Invalid conversion from field unit to 0b{3b}", conversion); + return BAN::Error::from_errno(EINVAL); + } + + if (source.as.field_unit.type == FieldUnit::Type::BankField) + { + Node bank_node; + bank_node.type = Node::Type::Integer; + bank_node.as.integer.value = source.as.field_unit.as.bank_field.bank_value; + TRY(store_to_field_unit(bank_node, source.as.field_unit.as.bank_field.bank_selector->node)); + } + + Node result = TRY(allocate_destination(source, target_type, max_length)); + const auto [dst_buf, dst_bytes] = TRY(extract_buffer_info(result)); + const auto [max_acc_bits, lock, _] = parse_access_rule(source.as.field_unit.flags); + + const size_t transfer_bits = BAN::Math::min(source.as.field_unit.length, dst_bytes * 8); + + size_t bits_done = 0; + while (bits_done < transfer_bits) + { + const size_t acc_bit_offset = (source.as.field_unit.offset + bits_done) & (max_acc_bits - 1); + const size_t acc_bit_count = max_acc_bits - acc_bit_offset; + const size_t acc_byte_offset = ((source.as.field_unit.offset + bits_done) & ~(max_acc_bits - 1)) / 8; + + uint64_t value = 0; + switch (source.as.field_unit.type) + { + case FieldUnit::Type::Field: + value = TRY(perform_opregion_read(source.as.field_unit.as.field.opregion, max_acc_bits / 8, acc_byte_offset)); + break; + case FieldUnit::Type::IndexField: + value = TRY(perform_index_field_read(source, acc_byte_offset)); + break; + case FieldUnit::Type::BankField: + value = TRY(perform_opregion_read(source.as.field_unit.as.bank_field.opregion, max_acc_bits / 8, acc_byte_offset)); + break; + } + + write_bits_to_buffer(const_cast(dst_buf), bits_done, value >> acc_bit_offset, acc_bit_count); + + bits_done += acc_bit_count; + } + + return result; + } + + BAN::ErrorOr store_to_field_unit(const Node& source, const Node& target) + { + ASSERT(target.type == Node::Type::FieldUnit); + + switch (source.type) + { + case Node::Type::Integer: + case Node::Type::Buffer: + case Node::Type::String: + break; + default: + return store_to_field_unit( + TRY(convert_node(TRY(source.copy()), ConvInteger | ConvBuffer | ConvString, 0xFFFFFFFFFFFFFFFF)), + target + ); + } + + if (target.as.field_unit.type == FieldUnit::Type::BankField) + { + Node bank_node; + bank_node.type = Node::Type::Integer; + bank_node.as.integer.value = target.as.field_unit.as.bank_field.bank_value; + TRY(store_to_field_unit(bank_node, target.as.field_unit.as.bank_field.bank_selector->node)); + } + + const auto [src_buf, src_bytes] = TRY(extract_buffer_info(source)); + const auto [max_acc_bits, lock, update_rule] = parse_access_rule(target.as.field_unit.flags); + + const size_t transfer_bits = BAN::Math::min(target.as.field_unit.length, src_bytes * 8); + + size_t bits_done = 0; + while (bits_done < transfer_bits) + { + const size_t acc_bit_offset = (target.as.field_unit.offset + bits_done) & (max_acc_bits - 1); + const size_t acc_bit_count = BAN::Math::min(max_acc_bits - acc_bit_offset, transfer_bits - bits_done); + const size_t acc_byte_offset = ((target.as.field_unit.offset + bits_done) & ~(max_acc_bits - 1)) / 8; + + uint64_t value; + switch (update_rule) + { + case AccessRule::Preserve: + switch (target.as.field_unit.type) + { + case FieldUnit::Type::Field: + value = TRY(perform_opregion_read(target.as.field_unit.as.field.opregion, max_acc_bits / 8, acc_byte_offset)); + break; + case FieldUnit::Type::IndexField: + value = TRY(perform_index_field_read(target, acc_byte_offset)); + break; + case FieldUnit::Type::BankField: + value = TRY(perform_opregion_read(target.as.field_unit.as.bank_field.opregion, max_acc_bits / 8, acc_byte_offset)); + break; + default: + ASSERT_NOT_REACHED(); + } + break; + case AccessRule::WriteZeros: + value = 0x0000000000000000; + break; + case AccessRule::WriteOnes: + value = 0xFFFFFFFFFFFFFFFF; + break; + default: + ASSERT_NOT_REACHED(); + } + + value &= ~(((static_cast(1) << acc_bit_count) - 1) << acc_bit_offset); + value |= read_bits_from_buffer(src_buf, bits_done, acc_bit_count) << acc_bit_offset; + + switch (target.as.field_unit.type) + { + case FieldUnit::Type::Field: + TRY(perform_opregion_write(target.as.field_unit.as.field.opregion, max_acc_bits / 8, acc_byte_offset, value)); + break; + case FieldUnit::Type::IndexField: + TRY(perform_index_field_write(target, acc_byte_offset, value)); + break; + case FieldUnit::Type::BankField: + TRY(perform_opregion_write(target.as.field_unit.as.bank_field.opregion, max_acc_bits / 8, acc_byte_offset, value)); + break; + default: + ASSERT_NOT_REACHED(); + } + + bits_done += acc_bit_count; + } + + return {}; + } + +} diff --git a/kernel/kernel/ACPI/AML/Package.cpp b/kernel/kernel/ACPI/AML/Package.cpp deleted file mode 100644 index eb30f91e..00000000 --- a/kernel/kernel/ACPI/AML/Package.cpp +++ /dev/null @@ -1,57 +0,0 @@ -#include - -namespace Kernel::ACPI -{ - - AML::ParseResult AML::Package::parse(AML::ParseContext& context) - { - ASSERT(context.aml_data.size() >= 1); - ASSERT(static_cast(context.aml_data[0]) == Byte::PackageOp); - context.aml_data = context.aml_data.slice(1); - - auto package_pkg = AML::parse_pkg(context.aml_data); - if (!package_pkg.has_value()) - return ParseResult::Failure; - - auto package_context = context; - package_context.aml_data = package_pkg.value(); - - if (package_pkg->size() < 1) - return ParseResult::Failure; - uint8_t num_elements = package_context.aml_data[0]; - package_context.aml_data = package_context.aml_data.slice(1); - - auto package = MUST(BAN::RefPtr::create(context.scope)); - while (package->elements.size() < num_elements && package_context.aml_data.size() > 0) - { - auto element_result = PackageElement::parse(package_context, package); - if (!element_result.success()) - return ParseResult::Failure; - ASSERT(element_result.node() && element_result.node()->type == Node::Type::PackageElement); - auto element = static_cast(element_result.node().ptr()); - MUST(package->elements.push_back(element)); - } - while (package->elements.size() < num_elements) - { - auto uninitialized = MUST(BAN::RefPtr::create(package)); - MUST(package->elements.push_back(uninitialized)); - } - - return ParseResult(package); - } - - void AML::Package::debug_print(int indent) const - { - AML_DEBUG_PRINT_INDENT(indent); - AML_DEBUG_PRINT("Package {"); - AML_DEBUG_PRINTLN(""); - for (const auto& element : elements) - { - element->debug_print(indent + 1); - AML_DEBUG_PRINTLN(""); - } - AML_DEBUG_PRINT_INDENT(indent); - AML_DEBUG_PRINT("}"); - } - -} diff --git a/kernel/kernel/ACPI/AML/Register.cpp b/kernel/kernel/ACPI/AML/Register.cpp deleted file mode 100644 index 7ca9a689..00000000 --- a/kernel/kernel/ACPI/AML/Register.cpp +++ /dev/null @@ -1,71 +0,0 @@ -#include -#include - -namespace Kernel::ACPI -{ - - AML::Register::Register() - : Node(Node::Type::Register) - {} - AML::Register::Register(BAN::RefPtr node) - : Node(Node::Type::Register) - { - if (!node) - { - value = node; - return; - } - - while (node) - { - if (node->type == AML::Node::Type::Reference) - node = static_cast(node.ptr())->node; - else if (node->type != AML::Node::Type::Buffer && node->type != AML::Node::Type::Package) - node = node->copy(); - if (node->type == AML::Node::Type::Register) - { - node = static_cast(node.ptr())->value; - continue; - } - break; - } - ASSERT(node); - value = node; - } - - BAN::RefPtr AML::Register::convert(uint8_t mask) - { - if (!value) - { - AML_ERROR("Trying to convert null Register"); - return {}; - } - return value->convert(mask); - } - - BAN::RefPtr AML::Register::store(BAN::RefPtr source) - { - if (source && source->type == AML::Node::Type::Register) - source = static_cast(source.ptr())->value; - if (value && value->type == AML::Node::Type::Reference) - return value->store(source); - value = source->copy(); - return value; - } - - void AML::Register::debug_print(int indent) const - { - AML_DEBUG_PRINT_INDENT(indent); - if (!value) - AML_DEBUG_PRINT("Register { No value }"); - else - { - AML_DEBUG_PRINTLN("Register { "); - value->debug_print(indent + 1); - AML_DEBUG_PRINTLN(""); - AML_DEBUG_PRINT_INDENT(indent); - AML_DEBUG_PRINT(" }"); - } - } - -} diff --git a/kernel/kernel/ACPI/AML/Scope.cpp b/kernel/kernel/ACPI/AML/Scope.cpp index e0a3e560..ea7c3afb 100644 --- a/kernel/kernel/ACPI/AML/Scope.cpp +++ b/kernel/kernel/ACPI/AML/Scope.cpp @@ -1,205 +1,65 @@ -#include -#include -#include -#include -#include +#include #include -namespace Kernel::ACPI +namespace Kernel::ACPI::AML { - AML::ParseResult AML::Scope::parse(ParseContext& context) + BAN::ErrorOr initialize_scope(const Scope& scope) { - ASSERT(context.aml_data.size() >= 1); - ASSERT(static_cast(context.aml_data[0]) == AML::Byte::ScopeOp); - context.aml_data = context.aml_data.slice(1); - - auto scope_pkg = AML::parse_pkg(context.aml_data); - if (!scope_pkg.has_value()) - return ParseResult::Failure; - - auto name_string = AML::NameString::parse(scope_pkg.value()); - if (!name_string.has_value()) - return ParseResult::Failure; - - auto named_object = Namespace::root_namespace()->find_object(context.scope, name_string.value(), Namespace::FindMode::Normal); - if (!named_object) - { - AML_PRINT("Scope '{}' not found in namespace", name_string.value()); - return ParseResult::Success; - } - if (!named_object->is_scope()) - { - AML_ERROR("Scope '{}' does not name a namespace", name_string.value()); - return ParseResult::Failure; - } - - auto* scope = static_cast(named_object.ptr()); - return scope->enter_context_and_parse_term_list(context, name_string.value(), scope_pkg.value()); - } - - AML::ParseResult AML::Scope::enter_context_and_parse_term_list(ParseContext& outer_context, const AML::NameString& name_string, BAN::ConstByteSpan aml_data) - { - auto resolved_scope = Namespace::root_namespace()->resolve_path(outer_context.scope, name_string, Namespace::FindMode::Normal); - if (!resolved_scope.has_value()) - return ParseResult::Failure; - - ParseContext scope_context; - scope_context.scope = AML::NameString(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; - } - - for (auto& name : scope_context.created_objects) - MUST(outer_context.created_objects.push_back(BAN::move(name))); - - return ParseResult::Success; - } - - static BAN::RefPtr evaluate_or_invoke(BAN::RefPtr object) - { - if (object->type != AML::Node::Type::Method) - { - auto converted = object->convert(AML::Node::ConvInteger); - if (!converted) - return {}; - return static_cast(converted.ptr()); - } - - auto* method = static_cast(object.ptr()); - if (method->arg_count != 0) - { - AML_ERROR("Method has {} arguments, expected 0", method->arg_count); - return {}; - } - - auto result = method->invoke(); - if (!result.has_value()) - { - AML_ERROR("Failed to evaluate method"); - return {}; - } - - auto result_integer = result.value() - ? result.value()->convert(AML::Node::ConvInteger) - : BAN::RefPtr(); - if (!result_integer) - return {}; - return static_cast(result_integer.ptr()); - } - - bool AML::initialize_scope(BAN::RefPtr scope) - { -#if AML_DEBUG_LEVEL >= 2 - AML_DEBUG_PRINTLN("Initializing {}", scope->scope); -#endif - - if (auto reg = Namespace::root_namespace()->find_object(scope->scope, AML::NameString("_REG"_sv), Namespace::FindMode::ForceAbsolute)) - { - bool embedded_controller = false; - Namespace::for_each_child(scope->scope, - [&](const auto&, auto& child) - { - if (child->type != AML::Node::Type::OpRegion) - return; - auto* region = static_cast(child.ptr()); - if (region->region_space == AML::OpRegion::RegionSpace::EmbeddedController) - embedded_controller = true; - } - ); - if (embedded_controller) - { - if (reg->type != AML::Node::Type::Method) - { - AML_ERROR("Object {}._REG is not a method", scope->scope); - return false; - } - - auto* method = static_cast(reg.ptr()); - if (method->arg_count != 2) - { - AML_ERROR("Method {}._REG has {} arguments, expected 2", scope->scope, method->arg_count); - return false; - } - - BAN::RefPtr embedded_controller = MUST(BAN::RefPtr::create(static_cast(AML::OpRegion::RegionSpace::EmbeddedController))); - - if (!method->invoke(embedded_controller, AML::Integer::Constants::One).has_value()) - { - AML_ERROR("Failed to evaluate {}._REG(EmbeddedController, 1), ignoring device", scope->scope); - return false; - } - } - } - bool run_ini = true; bool init_children = true; - if (auto sta = Namespace::root_namespace()->find_object(scope->scope, AML::NameString("_STA"_sv), Namespace::FindMode::ForceAbsolute)) + if (auto [sta_path, sta_obj] = TRY(Namespace::root_namespace().find_named_object(scope, TRY(NameString::from_string("_STA"_sv)), true)); sta_obj) { - auto result = evaluate_or_invoke(sta); - if (!result) + auto sta_result = TRY(evaluate_node(sta_path, sta_obj->node)); + if (sta_result.type != Node::Type::Integer) { - AML_ERROR("Failed to evaluate {}._STA, return value could not be resolved to integer", scope->scope); - return false; + dwarnln("Object {} evaluated to {}", sta_path, sta_result); + return BAN::Error::from_errno(EFAULT); } - run_ini = (result->value & 0x01); - init_children = run_ini || (result->value & 0x02); + run_ini = (sta_result.as.integer.value & 0x01); + init_children = run_ini || (sta_result.as.integer.value & 0x02); } if (run_ini) { - auto ini = Namespace::root_namespace()->find_object(scope->scope, AML::NameString("_INI"_sv), Namespace::FindMode::ForceAbsolute); - if (ini) + if (auto [ini_path, ini_obj] = TRY(Namespace::root_namespace().find_named_object(scope, TRY(NameString::from_string("_INI"_sv)), true)); ini_obj) { - if (ini->type != AML::Node::Type::Method) + auto& ini_node = ini_obj->node; + + if (ini_node.type != Node::Type::Method) { - AML_ERROR("Object {}._INI is not a method", scope->scope); - return false; + dwarnln("Object {} is not a method", ini_path); + return BAN::Error::from_errno(EFAULT); } - auto* method = static_cast(ini.ptr()); - if (method->arg_count != 0) + if (ini_node.as.method.arg_count != 0) { - AML_ERROR("Method {}._INI has {} arguments, expected 0", scope->scope, method->arg_count); - return false; + dwarnln("Method {} takes {} arguments, expected 0", ini_path, ini_node.as.method.arg_count); + return BAN::Error::from_errno(EFAULT); } - auto result = method->invoke(); - if (!result.has_value()) - { - AML_ERROR("Failed to evaluate {}._INI, ignoring device", scope->scope); - return true; - } + TRY(method_call(ini_path, ini_node, {})); } } - bool success = true; + BAN::ErrorOr result {}; if (init_children) { - Namespace::root_namespace()->for_each_child(scope->scope, - [&](const auto&, auto& child) + TRY(Namespace::root_namespace().for_each_child(scope, + [&result](const Scope& child_path, Reference* child) -> BAN::Iteration { - if (!child->is_scope()) - return; - auto* child_scope = static_cast(child.ptr()); - if (!initialize_scope(child_scope)) - success = false; + if (!child->node.is_scope()) + return BAN::Iteration::Continue; + if (auto ret = initialize_scope(child_path); ret.is_error()) + result = ret.release_error(); + return BAN::Iteration::Continue; } - ); + )); } - return success; + + return result; } } diff --git a/kernel/kernel/ACPI/AML/String.cpp b/kernel/kernel/ACPI/AML/String.cpp deleted file mode 100644 index a0f8db45..00000000 --- a/kernel/kernel/ACPI/AML/String.cpp +++ /dev/null @@ -1,75 +0,0 @@ -#include -#include - -namespace Kernel::ACPI::AML -{ - - BAN::Optional String::logical_compare(BAN::RefPtr node, AML::Byte binaryop) - { - auto rhs = node ? node->convert(AML::Node::ConvString) : BAN::RefPtr(); - if (!rhs) - { - AML_ERROR("String logical compare RHS is not string"); - return {}; - } - - (void)binaryop; - AML_TODO("Logical compare string"); - return {}; - } - - BAN::RefPtr String::as_buffer() - { - auto buffer = MUST(BAN::RefPtr::create()); - MUST(buffer->buffer.resize(string.size())); - for (size_t i = 0; i < string.size(); i++) - buffer->buffer[i] = string[i]; - return buffer; - } - - BAN::RefPtr String::convert(uint8_t mask) - { - if (mask & AML::Node::ConvString) - return this; - if (mask & AML::Node::ConvInteger) - { - // Apparently this is what NT does, but its definitely not spec compliant :D - uint64_t value = 0; - const size_t bytes = BAN::Math::min(string.size(), sizeof(value)); - memcpy(&value, string.data(), bytes); - return MUST(BAN::RefPtr::create(value)); - } - if (mask & AML::Node::ConvBuffer) - return as_buffer(); - return {}; - } - - ParseResult String::parse(ParseContext& context) - { - ASSERT(context.aml_data.size() >= 1); - ASSERT(static_cast(context.aml_data[0]) == AML::Byte::StringPrefix); - context.aml_data = context.aml_data.slice(1); - - BAN::Vector 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::create()); - string_node->string = BAN::move(string); - - return ParseResult(string_node); - } - -} diff --git a/kernel/kernel/Process.cpp b/kernel/kernel/Process.cpp index daf858eb..b0063f35 100644 --- a/kernel/kernel/Process.cpp +++ b/kernel/kernel/Process.cpp @@ -1588,7 +1588,7 @@ namespace Kernel [[noreturn]] static void reset_system() { - ACPI::ACPI::get().reset(); + (void)ACPI::ACPI::get().reset(); dwarnln("Could not reset with ACPI, crashing the cpu"); @@ -1608,9 +1608,8 @@ namespace Kernel if (command == POWEROFF_REBOOT) reset_system(); - ACPI::ACPI::get().poweroff(); - - return BAN::Error::from_errno(EUNKNOWN); + TRY(ACPI::ACPI::get().poweroff()); + ASSERT_NOT_REACHED(); } BAN::ErrorOr Process::sys_poweroff(int command)