diff --git a/kernel/CMakeLists.txt b/kernel/CMakeLists.txt index 4b8b2a15..61666bbb 100644 --- a/kernel/CMakeLists.txt +++ b/kernel/CMakeLists.txt @@ -12,10 +12,11 @@ set(KERNEL_SOURCES font/prefs.psf.o kernel/ACPI/ACPI.cpp kernel/ACPI/AML.cpp - kernel/ACPI/AML/DataObject.cpp - kernel/ACPI/AML/MiscObject.cpp - kernel/ACPI/AML/NameObject.cpp - kernel/ACPI/AML/TermObject.cpp + kernel/ACPI/AML/Field.cpp + kernel/ACPI/AML/NamedObject.cpp + kernel/ACPI/AML/Namespace.cpp + kernel/ACPI/AML/Node.cpp + kernel/ACPI/AML/Scope.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 80221c62..323677af 100644 --- a/kernel/include/kernel/ACPI/ACPI.h +++ b/kernel/include/kernel/ACPI/ACPI.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include @@ -32,6 +33,8 @@ namespace Kernel::ACPI SDTHeader* as_header() { return (SDTHeader*)vaddr; } }; BAN::Vector m_mapped_headers; + + BAN::RefPtr m_namespace; }; } diff --git a/kernel/include/kernel/ACPI/AML.h b/kernel/include/kernel/ACPI/AML.h index 6e3e1f07..5f0185ce 100644 --- a/kernel/include/kernel/ACPI/AML.h +++ b/kernel/include/kernel/ACPI/AML.h @@ -1,6 +1,7 @@ #pragma once #include +#include namespace Kernel::ACPI { @@ -10,7 +11,7 @@ namespace Kernel::ACPI public: ~AMLParser(); - static AMLParser parse_table(const SDTHeader& header); + static BAN::RefPtr parse_table(const SDTHeader& header); private: AMLParser(); diff --git a/kernel/include/kernel/ACPI/AML/Buffer.h b/kernel/include/kernel/ACPI/AML/Buffer.h new file mode 100644 index 00000000..9f8858ae --- /dev/null +++ b/kernel/include/kernel/ACPI/AML/Buffer.h @@ -0,0 +1,60 @@ +#pragma once + +#include +#include +#include +#include + +namespace Kernel::ACPI::AML +{ + + struct Buffer : public AML::Node + { + BAN::Vector buffer; + + Buffer() : AML::Node(Node::Type::Buffer) {} + + 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_object = AML::parse_object(buffer_context); + if (!buffer_size_object.success()) + return ParseResult::Failure; + + auto buffer_size = buffer_size_object.node()->as_integer(); + if (!buffer_size.has_value()) + return ParseResult::Failure; + + uint32_t actual_buffer_size = BAN::Math::max(buffer_size.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()); + } + }; + +} diff --git a/kernel/include/kernel/ACPI/AML/Bytes.h b/kernel/include/kernel/ACPI/AML/Bytes.h index 204a8e1a..22252073 100644 --- a/kernel/include/kernel/ACPI/AML/Bytes.h +++ b/kernel/include/kernel/ACPI/AML/Bytes.h @@ -1,265 +1,163 @@ #pragma once -#include -#include -#include -#include - -#define DUMP_AML 0 - -#if DUMP_AML - -#define AML_DEBUG_CONCAT_IMPL(x, y) x##y -#define AML_DEBUG_CONCAT(x, y) AML_DEBUG_CONCAT_IMPL(x, y) -#define AML_DEBUG_INDENT_SCOPE() Kernel::ACPI::AML::Indenter AML_DEBUG_CONCAT(indenter, __COUNTER__) - -#define __AML_DEBUG_PRINT_INDENT() \ - do { \ - BAN::Formatter::print(Debug::putchar, "{}:{3} ", __BASE_FILE__, __LINE__); \ - for (size_t i = 1; i < AML::g_depth; i++) \ - BAN::Formatter::print(Debug::putchar, "│ "); \ - if (AML::g_depth > 0) \ - BAN::Formatter::print(Debug::putchar, "├─"); \ - } while (0) - -#define AML_DEBUG_PRINT_FN() \ - __AML_DEBUG_PRINT_INDENT(); \ - AML_DEBUG_INDENT_SCOPE(); \ - BAN::Formatter::println(Debug::putchar, "{}", AML::get_class_name(__PRETTY_FUNCTION__)) - -#define AML_DEBUG_PRINT(...) \ - do { \ - __AML_DEBUG_PRINT_INDENT(); \ - BAN::Formatter::println(Debug::putchar, __VA_ARGS__); \ - } while (0) - -#else - -#define AML_DEBUG_PRINT_FN() -#define AML_DEBUG_PRINT(...) -#define AML_DEBUG_INDENT_SCOPE() -#define __AML_DEBUG_PRINT_INDENT() - -#endif - -#define AML_DEBUG_TODO(...) \ - do { \ - __AML_DEBUG_PRINT_INDENT(); \ - 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_DEBUG_ERROR(...) \ - do { \ - __AML_DEBUG_PRINT_INDENT(); \ - BAN::Formatter::print(Debug::putchar, "\e[31m"); \ - BAN::Formatter::print(Debug::putchar, __VA_ARGS__); \ - BAN::Formatter::println(Debug::putchar, "\e[m"); \ - } while (0) - -#define AML_DEBUG_CANNOT_PARSE(TYPE, SPAN) \ - do { \ - __AML_DEBUG_PRINT_INDENT(); \ - BAN::Formatter::print(Debug::putchar, "\e[31mCannot parse " TYPE " (span {} bytes", SPAN.size()); \ - if (SPAN.size() > 0) \ - BAN::Formatter::print(Debug::putchar, ", {2H}", SPAN[0]); \ - if (SPAN.size() > 1) \ - BAN::Formatter::print(Debug::putchar, " {2H}", SPAN[1]); \ - BAN::Formatter::println(Debug::putchar, ")\e[m"); \ - } while (0) +#include namespace Kernel::ACPI::AML { - extern size_t g_depth; - struct Indenter - { - Indenter() { g_depth++; } - ~Indenter() { g_depth--; } - }; - - static BAN::StringView get_class_name(BAN::StringView pretty_function) - { - return MUST(MUST(pretty_function.split(' '))[2].split(':'))[3]; - } -} - -#define GEN_PARSE_CASE_TODO(NAME) \ - case AML::Byte::NAME: \ - AML_DEBUG_TODO(#NAME); \ - return {}; - -#define AML_TRY_PARSE_PACKAGE(NAME) \ - auto opt_##NAME = AML::PkgLength::parse_package(span); \ - if (!opt_##NAME.has_value()) \ - return {}; \ - auto NAME = opt_##NAME.release_value(); - -#define AML_TRY_PARSE(NAME, TYPE, SPAN) \ - if (!TYPE::can_parse(SPAN)) \ - { \ - AML_DEBUG_CANNOT_PARSE(#TYPE, SPAN); \ - return {}; \ - } \ - auto NAME = TYPE::parse(SPAN); \ - if (!NAME.has_value()) \ - return {} - -#define AML_TRY_PARSE_IF_CAN(TYPE) \ - if (TYPE::can_parse(span)) \ - { \ - if (auto obj = TYPE::parse(span); obj.has_value()) \ - return obj.release_value(); \ - return {}; \ - } - - - -namespace Kernel::ACPI::AML { - - enum class Byte : uint8_t + + enum class Byte { + NullName = 0x00, + ZeroOp = 0x00, + OneOp = 0x01, + // 0x02 - 0x05 + AliasOp = 0x06, + // 0x07 + NameOp = 0x08, + // 0x09 + BytePrefix = 0x0A, + WordPrefix = 0x0B, + DWordPrefix = 0x0C, + StringPrefix = 0x0D, + QWordPrefix = 0x0E, + // 0x0F + ScopeOp = 0x10, + BufferOp = 0x11, + PackageOp = 0x12, + VarPackageOp = 0x13, + MethodOp = 0x14, + ExternalOp = 0x15, + // 0x16 - 0x2D + DualNamePrefix = 0x2E, + MultiNamePrefix = 0x2F, + // 0x30 - 0x39 DigitChar + // 0x3A - 0x40 + // 0x41 - 0x5A NameChar ExtOpPrefix = 0x5B, - - // NamePath - DualNamePrefix = 0x2E, - MultiNamePrefix = 0x2F, - - // NameSpaceModifierObj - AliasOp = 0x06, - NameOp = 0x08, - ScopeOp = 0x10, - - // ConstObj - ZeroOp = 0x00, - OneOp = 0x01, - OnesOp = 0xFF, - - // ComputationalData - BytePrefix = 0x0A, - WordPrefix = 0x0B, - DWordPrefix = 0x0C, - StringPrefix = 0x0D, - QWordPrefix = 0x0E, - BufferOp = 0x11, - ExtRevisionOp = 0x30, - - // DataObject - PackageOp = 0x12, - VarPackageOp = 0x13, - - // NamedObj - ExternalOp = 0x15, - CreateDWordFieldOp = 0x8A, - CreateWordFieldOp = 0x8B, - CreateByteFieldOp = 0x8C, - CreateBitFieldOp = 0x8D, - CreateQWordFieldOp = 0x8F, - ExtCreateFieldOp = 0x13, - ExtOpRegionOp = 0x80, - ExtProcessorOp = 0x83, // deprecated - ExtPowerResOp = 0x84, - ExtThermalZoneOp = 0x85, - ExtBankFieldOp = 0x87, - ExtDataRegionOp = 0x88, - // ... not specified - MethodOp = 0x14, - ExtMutexOp = 0x01, - ExtEventOp = 0x02, - ExtFieldOp = 0x81, - ExtDeviceOp = 0x82, - ExtIndexFieldOp = 0x86, - - // StatementOpcode - BreakOp = 0xA5, - BreakPointOp = 0xCC, - ContinueOp = 0x9F, - ElseOp = 0xA1, - IfOp = 0xA0, - NoopOp = 0xA3, - NotifyOp = 0x86, - ReturnOp = 0xA4, - WhileOp = 0xA2, - ExtFatalOp = 0x32, - ExtReleaseOp = 0x27, - ExtResetOp = 0x26, - ExtSignalOp = 0x24, - ExtSleepOp = 0x22, - ExtStallOp = 0x21, - - // ExpressionOpcode - //PackageOp = 0x12, - //VarPackageOp = 0x13, - //BufferOp = 0x11, - StoreOp = 0x70, - RefOfOp = 0x71, - AddOp = 0x72, - ConcatOp = 0x73, - SubtractOp = 0x74, - IncrementOp = 0x75, - DecrementOp = 0x76, - MultiplyOp = 0x77, - DivideOp = 0x78, - ShiftLeftOp = 0x79, - ShiftRightOp = 0x7A, - AndOp = 0x7B, - NAndOp = 0x7C, - OrOp = 0x7D, - NOrOp = 0x7E, - XOrOp = 0x7F, - NotOp = 0x80, - FindSetLeftBitOp = 0x81, - FindSetRightBitOp = 0x82, - DerefOfOp = 0x83, - ConcatResOp = 0x84, - ModOp = 0x85, - SizeOfOp = 0x87, - IndexOp = 0x88, - MatchOp = 0x89, - ObjectTypeOp = 0x8E, - LAndOp = 0x90, - LOrOp = 0x91, - LNotOp = 0x92, - LEqualOp = 0x93, - LGreaterOp = 0x94, - LLessOp = 0x95, - ToBufferOp = 0x96, - ToDecimalStringOp = 0x97, - ToHexStringOp = 0x98, - ToIntegerOp = 0x99, - ToStringOp = 0x9C, - CopyObjectOp = 0x9D, - MidOp = 0x9E, - ExtCondRefOfOp = 0x12, - ExtLoadTableOp = 0x1F, - ExtLoadOp = 0x20, - ExtAcquireOp = 0x23, - ExtWaitOp = 0x25, - ExtFromBCDOp = 0x28, - ExtToBCDOp = 0x29, - ExtTimerOp = 0x33, - - // LocalObj - Local0Op = 0x60, - Local1Op = 0x61, - Local2Op = 0x62, - Local3Op = 0x63, - Local4Op = 0x64, - Local5Op = 0x65, - Local6Op = 0x66, - Local7Op = 0x67, - - // ArgObj - Arg0Op = 0x68, - Arg1Op = 0x69, - Arg2Op = 0x6A, - Arg3Op = 0x6B, - Arg4Op = 0x6C, - Arg5Op = 0x6D, - Arg6Op = 0x6E, - - // DebugObj - ExtDebugOp = 0x31, + RootChar = 0x5C, + // 0x5D + ParentPrefixChar = 0x5E, + // 0x5F NameChar + Local0 = 0x60, + Local1 = 0x61, + Local2 = 0x62, + Local3 = 0x63, + Local4 = 0x64, + Local5 = 0x65, + Local6 = 0x66, + Local7 = 0x67, + Arg0 = 0x68, + Arg1 = 0x69, + Arg2 = 0x6A, + Arg3 = 0x6B, + Arg4 = 0x6C, + Arg5 = 0x6D, + Arg6 = 0x6E, + // 0x6F + StoreOp = 0x70, + RefOfOp = 0x71, + AddOp = 0x72, + ConcatOp = 0x73, + SubtractOp = 0x74, + IncrementOp = 0x75, + DecrementOp = 0x76, + MultiplyOp = 0x77, + DivideOp = 0x78, + ShiftLeftOp = 0x79, + ShiftRightOp = 0x7A, + AndOp = 0x7B, + NandOp = 0x7C, + OrOp = 0x7D, + NorOp = 0x7E, + XorOp = 0x7F, + NotOp = 0x80, + FindSetLeftBitOp = 0x81, + FindSetRightBitOp = 0x82, + DerefOfOp = 0x83, + ConcatResOp = 0x84, + ModOp = 0x85, + NotifyOp = 0x86, + SizeOfOp = 0x87, + IndexOp = 0x88, + MatchOp = 0x89, + CreateDWordFieldOp = 0x8A, + CreateWordFieldOp = 0x8B, + CreateByteFieldOp = 0x8C, + CreateBitFieldOp = 0x8D, + ObjectTypeOp = 0x8E, + CreateQWordFieldOp = 0x8F, + LAndOp = 0x90, + LOrOp = 0x91, + LNotOp = 0x92, + LEqualOp = 0x93, + LGreaterOp = 0x94, + LLessOp = 0x95, + ToBufferOp = 0x96, + ToDecimalStringOp = 0x97, + ToHexStringOp = 0x98, + ToIntegerOp = 0x99, + // 0x9A - 0x9B + ToStringOp = 0x9C, + CopyObjectOp = 0x9D, + MidOp = 0x9E, + ContinueOp = 0x9F, + IfOp = 0xA0, + ElseOp = 0xA1, + WhileOp = 0xA2, + NoopOp = 0xA3, + ReturnOp = 0xA4, + BreakOp = 0xA5, + // 0xA6 - 0xCB + BreakPointOp = 0xCC, + // 0xCD - 0xFE + OnesOp = 0xFF, }; + enum class ExtOp + { + MutexOp = 0x01, + EventOp = 0x02, + CondRefOfOp = 0x12, + CreateFieldOp = 0x13, + LoadTableOp = 0x1F, + LoadOp = 0x20, + StallOp = 0x21, + SleepOp = 0x22, + AcquireOp = 0x23, + SignalOp = 0x24, + WaitOp = 0x25, + ResetOp = 0x26, + ReleaseOp = 0x27, + FromBCDOp = 0x28, + ToBCDOp = 0x29, + RevisionOp = 0x30, + DebugOp = 0x31, + FatalOp = 0x32, + TimerOp = 0x33, + OpRegionOp = 0x80, + FieldOp = 0x81, + DeviceOp = 0x82, + ProcessorOp = 0x83, + PowerResOp = 0x84, + ThermalZoneOp = 0x85, + IndexFieldOp = 0x86, + BankFieldOp = 0x87, + DataRegionOp = 0x88, + }; + + static constexpr bool is_digit_char(uint8_t ch) + { + return '0' <= ch && ch <= '9'; + } + + static constexpr bool is_lead_name_char(uint8_t ch) + { + return ('A' <= ch && ch <= 'Z') || ch == '_'; + } + + static constexpr bool is_name_char(uint8_t ch) + { + return is_lead_name_char(ch) || is_digit_char(ch); + } + } diff --git a/kernel/include/kernel/ACPI/AML/DataObject.h b/kernel/include/kernel/ACPI/AML/DataObject.h deleted file mode 100644 index e93ef2f5..00000000 --- a/kernel/include/kernel/ACPI/AML/DataObject.h +++ /dev/null @@ -1,102 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include -#include - -namespace Kernel::ACPI::AML -{ - // ACPI Spec 6.4, Section 20.2.3 - - // Integer := ByteConst | WordConst | DWordConst | QWordConst - // Not actually defined in the spec... - struct Integer - { - uint64_t value; - - static bool can_parse(BAN::ConstByteSpan span); - static BAN::Optional parse(BAN::ConstByteSpan& span); - }; - - // Buffer := BufferOp PkgLength BufferSize ByteList - struct Buffer - { - Integer buffer_size; - BAN::Vector data; - - static bool can_parse(BAN::ConstByteSpan span); - static BAN::Optional parse(BAN::ConstByteSpan& span); - }; - - // ComputationalData := Integer | String | ConstObj | RevisionOp | DefBuffer - struct ComputationalData - { - struct String - { - BAN::String value; - }; - struct ConstObj - { - enum class Type - { - Zero, - One, - Ones - }; - Type type; - }; - struct RevisionOp {}; - - BAN::Variant data; - - static bool can_parse(BAN::ConstByteSpan span); - static BAN::Optional parse(BAN::ConstByteSpan& span); - }; - - struct DataRefObject; - struct Uninitialized {}; - - // PackageElement := DataRefObject | NameString - using PackageElement = BAN::Variant, NameString, Uninitialized>; - - // DefPackage := PackageOp PkgLength NumElements PackageElementList - struct Package - { - BAN::Vector elements; - - static bool can_parse(BAN::ConstByteSpan span); - static BAN::Optional parse(BAN::ConstByteSpan& span); - }; - - // DefVarPackage := VarPackageOp PkgLength VarNumElements PackageElementList - struct VarPackage - { - BAN::Vector elements; - - static bool can_parse(BAN::ConstByteSpan span); - static BAN::Optional parse(BAN::ConstByteSpan& span); - }; - - // DataObject := ComputationalData | DefPackage | DefVarPackage - struct DataObject - { - BAN::Variant data; - - static bool can_parse(BAN::ConstByteSpan span); - static BAN::Optional parse(BAN::ConstByteSpan& span); - }; - - // DataRefObject := DataObject | ObjectReference - struct DataRefObject - { - BAN::Variant object; - - static bool can_parse(BAN::ConstByteSpan span); - static BAN::Optional parse(BAN::ConstByteSpan& span); - }; - -} diff --git a/kernel/include/kernel/ACPI/AML/Device.h b/kernel/include/kernel/ACPI/AML/Device.h new file mode 100644 index 00000000..dadd0824 --- /dev/null +++ b/kernel/include/kernel/ACPI/AML/Device.h @@ -0,0 +1,52 @@ +#pragma once + +#include +#include +#include + +namespace Kernel::ACPI::AML +{ + + struct Device : public AML::Scope + { + Device(NameSeg name) : Scope(name, Node::Type::Device) {} + + 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 (!context.root_namespace->add_named_object(context.scope.span(), name_string.value(), device)) + return ParseResult::Failure; + + 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(" {"); + for (const auto& [name, object] : objects) + { + object->debug_print(indent + 1); + AML_DEBUG_PRINTLN(""); + } + AML_DEBUG_PRINT_INDENT(indent); + AML_DEBUG_PRINT("}"); + } + }; + +} diff --git a/kernel/include/kernel/ACPI/AML/Field.h b/kernel/include/kernel/ACPI/AML/Field.h new file mode 100644 index 00000000..6f1fbd97 --- /dev/null +++ b/kernel/include/kernel/ACPI/AML/Field.h @@ -0,0 +1,89 @@ +#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; + }; + + struct FieldElement : public NamedObject + { + uint64_t bit_offset; + uint32_t bit_count; + + FieldRules access_rules; + + OpRegion* op_region = nullptr; + + FieldElement(NameSeg name, uint64_t bit_offset, uint32_t bit_count, FieldRules access_rules) + : NamedObject(Node::Type::FieldElement, name) + , bit_offset(bit_offset) + , bit_count(bit_count) + , access_rules(access_rules) + {} + + void debug_print(int indent) const override; + }; + + struct Field + { + static ParseResult parse(ParseContext& context); + }; + + struct IndexFieldElement : public NamedObject + { + uint64_t bit_offset; + uint32_t bit_count; + + FieldRules access_rules; + + FieldElement* index_element = nullptr; + FieldElement* data_element = nullptr; + + IndexFieldElement(NameSeg name, uint64_t bit_offset, uint32_t bit_count, FieldRules access_rules) + : NamedObject(Node::Type::IndexFieldElement, name) + , bit_offset(bit_offset) + , bit_count(bit_count) + , access_rules(access_rules) + {} + + void debug_print(int indent) const override; + }; + + struct IndexField + { + static ParseResult parse(ParseContext& context); + }; + +} diff --git a/kernel/include/kernel/ACPI/AML/Integer.h b/kernel/include/kernel/ACPI/AML/Integer.h new file mode 100644 index 00000000..76659b25 --- /dev/null +++ b/kernel/include/kernel/ACPI/AML/Integer.h @@ -0,0 +1,92 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +namespace Kernel::ACPI::AML +{ + + struct Integer : public Node + { + static constexpr uint64_t Ones = -1; + uint64_t value; + + Integer(uint64_t value) : Node(Node::Type::Integer), value(value) {} + + BAN::Optional as_integer() const override + { + return value; + } + + static ParseResult parse(BAN::ConstByteSpan& aml_data) + { + switch (static_cast(aml_data[0])) + { + case AML::Byte::ZeroOp: + aml_data = aml_data.slice(1); + return ParseResult(MUST(BAN::RefPtr::create(0))); + case AML::Byte::OneOp: + aml_data = aml_data.slice(1); + return ParseResult(MUST(BAN::RefPtr::create(1))); + case AML::Byte::OnesOp: + aml_data = aml_data.slice(1); + return ParseResult(MUST(BAN::RefPtr::create(Ones))); + case AML::Byte::BytePrefix: + { + if (aml_data.size() < 2) + return ParseResult::Failure; + 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 = BAN::little_endian_to_host( + *reinterpret_cast(&aml_data[1]) + ); + 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 = BAN::little_endian_to_host( + *reinterpret_cast(&aml_data[1]) + ); + 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 = BAN::little_endian_to_host( + *reinterpret_cast(&aml_data[1]) + ); + aml_data = aml_data.slice(9); + return ParseResult(MUST(BAN::RefPtr::create(value))); + } + default: + ASSERT_NOT_REACHED(); + } + } + + void debug_print(int indent) const override + { + AML_DEBUG_PRINT_INDENT(indent); + if (value == Ones) + AML_DEBUG_PRINT("Ones"); + else + AML_DEBUG_PRINT("0x{H}", value); + } + }; + +} diff --git a/kernel/include/kernel/ACPI/AML/Method.h b/kernel/include/kernel/ACPI/AML/Method.h new file mode 100644 index 00000000..8c3154ba --- /dev/null +++ b/kernel/include/kernel/ACPI/AML/Method.h @@ -0,0 +1,78 @@ +#pragma once + +#include +#include +#include +#include + +namespace Kernel::ACPI::AML +{ + + struct Method : public AML::NamedObject + { + uint8_t arg_count; + bool serialized; + uint8_t sync_level; + + BAN::ConstByteSpan term_list; + + Method(AML::NameSeg name, uint8_t arg_count, bool serialized, uint8_t sync_level, BAN::ConstByteSpan term_list) + : AML::NamedObject(Node::Type::Method, name) + , arg_count(arg_count) + , serialized(serialized) + , sync_level(sync_level) + , term_list(term_list) + {} + + 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, + method_pkg.value() + )); + + if (!context.root_namespace->add_named_object(context.scope.span(), name_string.value(), method)) + return ParseResult::Failure; + +#if AML_DEBUG_LEVEL >= 2 + method->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("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/MiscObject.h b/kernel/include/kernel/ACPI/AML/MiscObject.h deleted file mode 100644 index 2e974b70..00000000 --- a/kernel/include/kernel/ACPI/AML/MiscObject.h +++ /dev/null @@ -1,56 +0,0 @@ -#pragma once - -#include -#include - -namespace Kernel::ACPI::AML -{ - // ACPI Spec 6.4, Section 20.2.6 - - // ArgObj := Arg0Op | Arg1Op | Arg2Op | Arg3Op | Arg4Op | Arg5Op | Arg6Op - struct ArgObj - { - enum class Type - { - Arg0, - Arg1, - Arg2, - Arg3, - Arg4, - Arg5, - Arg6, - }; - Type type; - - static bool can_parse(BAN::ConstByteSpan span); - static BAN::Optional parse(BAN::ConstByteSpan& span); - }; - - // LocalObj := Local0Op | Local1Op | Local2Op | Local3Op | Local4Op | Local5Op | Local6Op | Local7Op - struct LocalObj - { - enum class Type - { - Local0, - Local1, - Local2, - Local3, - Local4, - Local5, - Local6, - Local7, - }; - Type type; - - static bool can_parse(BAN::ConstByteSpan span); - static BAN::Optional parse(BAN::ConstByteSpan& span); - }; - - // DebugObj := DebugOp - struct DebugObj - { - static bool can_parse(BAN::ConstByteSpan span); - static BAN::Optional parse(BAN::ConstByteSpan& span); - }; - -} diff --git a/kernel/include/kernel/ACPI/AML/Mutex.h b/kernel/include/kernel/ACPI/AML/Mutex.h new file mode 100644 index 00000000..7d90cf3b --- /dev/null +++ b/kernel/include/kernel/ACPI/AML/Mutex.h @@ -0,0 +1,62 @@ +#pragma once + +#include +#include +#include + +namespace Kernel::ACPI::AML +{ + + struct Mutex : public AML::NamedObject + { + uint8_t sync_level; + + Mutex(NameSeg name, uint8_t sync_level) + : NamedObject(Node::Type::Mutex, name) + , sync_level(sync_level) + {} + + 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::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 (!context.root_namespace->add_named_object(context.scope.span(), name.value(), mutex)) + return ParseResult::Failure; + +#if AML_DEBUG_LEVEL >= 2 + mutex->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("Mutex "); + name.debug_print(); + AML_DEBUG_PRINT(" (SyncLevel: {})", sync_level); + } + }; + +} diff --git a/kernel/include/kernel/ACPI/AML/NameObject.h b/kernel/include/kernel/ACPI/AML/NameObject.h deleted file mode 100644 index 0cbd4e31..00000000 --- a/kernel/include/kernel/ACPI/AML/NameObject.h +++ /dev/null @@ -1,46 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include -#include - -namespace Kernel::ACPI::AML -{ - // ACPI Spec 6.4, Section 20.2.2 - - // NameSeg := LeadNameChar NameChar NameChar NameChar - // NameString := ('\' | {'^'}) (NameSeg | (DualNamePrefix NameSeg NameSeg) | (MultiNamePrefix SegCount NameSeg(SegCount)) | 0x00) - struct NameString - { - BAN::String prefix; - BAN::Vector path; - - static bool can_parse(BAN::ConstByteSpan span); - static BAN::Optional parse(BAN::ConstByteSpan& span); - }; - - // SimpleName := NameString | ArgObj | LocalObj - struct SimpleName - { - BAN::Variant name; - - static bool can_parse(BAN::ConstByteSpan span); - static BAN::Optional parse(BAN::ConstByteSpan& span); - }; - - struct ReferenceTypeOpcode; - - // SuperName := SimpleName | DebugObj | ReferenceTypeOpcode - struct SuperName - { - BAN::Variant> name; - - static bool can_parse(BAN::ConstByteSpan span); - static BAN::Optional parse(BAN::ConstByteSpan& span); - }; - -} diff --git a/kernel/include/kernel/ACPI/AML/NamedObject.h b/kernel/include/kernel/ACPI/AML/NamedObject.h new file mode 100644 index 00000000..5ec80c92 --- /dev/null +++ b/kernel/include/kernel/ACPI/AML/NamedObject.h @@ -0,0 +1,28 @@ +#pragma once + +#include +#include + +namespace Kernel::ACPI::AML +{ + + struct NamedObject : public Node + { + NameSeg name; + + NamedObject(Node::Type type, NameSeg name) : Node(type), name(name) {} + }; + + struct Name : public NamedObject + { + BAN::RefPtr object; + + Name(NameSeg name, BAN::RefPtr object) + : NamedObject(Node::Type::Name, name), object(BAN::move(object)) + {} + + 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 new file mode 100644 index 00000000..9df82345 --- /dev/null +++ b/kernel/include/kernel/ACPI/AML/Names.h @@ -0,0 +1,157 @@ +#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); + } + + 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; + + 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); + } + }; + +} diff --git a/kernel/include/kernel/ACPI/AML/Namespace.h b/kernel/include/kernel/ACPI/AML/Namespace.h new file mode 100644 index 00000000..758a2caf --- /dev/null +++ b/kernel/include/kernel/ACPI/AML/Namespace.h @@ -0,0 +1,23 @@ +#pragma once + +#include + +namespace Kernel::ACPI::AML +{ + + struct Namespace : public AML::Scope + { + Namespace() : AML::Scope(NameSeg("\\"sv)) {} + + static BAN::RefPtr parse(BAN::ConstByteSpan aml); + + BAN::Optional> resolve_path(BAN::Span parsing_scope, const AML::NameString& relative_path); + + // Find an object in the namespace. Returns nullptr if the object is not found. + BAN::RefPtr find_object(BAN::Span parsing_scope, const AML::NameString& relative_path); + + // Add an object to the namespace. Returns false if the parent object could not be added. + bool add_named_object(BAN::Span parsing_scope, const AML::NameString& object_path, BAN::RefPtr object); + }; + +} diff --git a/kernel/include/kernel/ACPI/AML/Node.h b/kernel/include/kernel/ACPI/AML/Node.h new file mode 100644 index 00000000..1a6200aa --- /dev/null +++ b/kernel/include/kernel/ACPI/AML/Node.h @@ -0,0 +1,69 @@ +#pragma once + +#include +#include +#include +#include + +namespace Kernel::ACPI::AML +{ + + struct Node : public BAN::RefCounted + { + enum class Type + { + Buffer, + Device, + FieldElement, + IndexFieldElement, + Integer, + Method, + Mutex, + Name, + OpRegion, + Package, + Processor, + Scope, + String, + }; + const Type type; + + Node(Type type) : type(type) {} + virtual ~Node() = default; + + virtual bool is_scope() const { return false; } + virtual BAN::Optional as_integer() const { return {}; } + + virtual void debug_print(int indent) const = 0; + }; + + struct ParseContext; + struct ParseResult + { + static ParseResult Failure; + static ParseResult Success; + + enum class Result + { + Success, + Failure, + }; + + ParseResult(Result success) : m_result(success) {} + ParseResult(BAN::RefPtr node) : m_result(Result::Success), m_node(BAN::move(node)) { ASSERT(m_node); } + + bool success() const { return m_result == Result::Success; } + + BAN::RefPtr node() + { + ASSERT(m_node); + return m_node; + } + + private: + Result m_result = Result::Failure; + BAN::RefPtr m_node; + }; + ParseResult parse_object(ParseContext& context); + +} diff --git a/kernel/include/kernel/ACPI/AML/Package.h b/kernel/include/kernel/ACPI/AML/Package.h new file mode 100644 index 00000000..3aa1d2c4 --- /dev/null +++ b/kernel/include/kernel/ACPI/AML/Package.h @@ -0,0 +1,66 @@ +#pragma once + +#include +#include +#include +#include + +namespace Kernel::ACPI::AML +{ + + struct Package : public AML::Node + { + BAN::Vector> elements; + + Package() : Node(Node::Type::Package) {} + + static ParseResult 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); + + BAN::Vector> elements; + while (elements.size() < num_elements && package_context.aml_data.size() > 0) + { + auto element_result = AML::parse_object(package_context); + if (!element_result.success()) + return ParseResult::Failure; + MUST(elements.push_back(element_result.node())); + } + while (elements.size() < num_elements) + MUST(elements.push_back(BAN::RefPtr())); + + auto package = MUST(BAN::RefPtr::create()); + package->elements = BAN::move(elements); + return ParseResult(package); + } + + virtual void debug_print(int indent) const override + { + 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/include/kernel/ACPI/AML/PackageLength.h b/kernel/include/kernel/ACPI/AML/PackageLength.h deleted file mode 100644 index 7184175b..00000000 --- a/kernel/include/kernel/ACPI/AML/PackageLength.h +++ /dev/null @@ -1,36 +0,0 @@ -#pragma once - -#include -#include -#include - -namespace Kernel::ACPI::AML -{ - - struct PkgLength - { - static BAN::Optional parse_package(BAN::ConstByteSpan& span) - { - if (span.size() < 1) - return {}; - - uint8_t count = (span[0] >> 6) + 1; - if (span.size() < count) - return {}; - if (count > 1 && (span[0] & 0x30)) - return {}; - - uint32_t length = span[0] & 0x3F; - for (uint8_t i = 1; i < count; i++) - length |= static_cast(span[i]) << (i * 8 - 4); - - if (span.size() < length) - return {}; - - auto result = span.slice(count, length - count); - span = span.slice(length); - return result; - } - }; - -} diff --git a/kernel/include/kernel/ACPI/AML/ParseContext.h b/kernel/include/kernel/ACPI/AML/ParseContext.h new file mode 100644 index 00000000..8cc0f2e9 --- /dev/null +++ b/kernel/include/kernel/ACPI/AML/ParseContext.h @@ -0,0 +1,18 @@ +#pragma once + +#include +#include +#include +#include + +namespace Kernel::ACPI::AML +{ + + struct ParseContext + { + BAN::ConstByteSpan aml_data; + BAN::Vector scope; + struct Namespace* root_namespace; + }; + +} diff --git a/kernel/include/kernel/ACPI/AML/Pkg.h b/kernel/include/kernel/ACPI/AML/Pkg.h new file mode 100644 index 00000000..a9898d98 --- /dev/null +++ b/kernel/include/kernel/ACPI/AML/Pkg.h @@ -0,0 +1,51 @@ +#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/Processor.h b/kernel/include/kernel/ACPI/AML/Processor.h new file mode 100644 index 00000000..2e91aa42 --- /dev/null +++ b/kernel/include/kernel/ACPI/AML/Processor.h @@ -0,0 +1,71 @@ +#pragma once + +#include +#include +#include +#include +#include + +namespace Kernel::ACPI::AML +{ + + struct Processor : 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(name, Node::Type::Processor) + , id(id) + , pblk_addr(pblk_addr) + , pblk_len(pblk_len) + {} + + 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 processor_pkg = AML::parse_pkg(context.aml_data); + if (!processor_pkg.has_value()) + return ParseResult::Failure; + + auto name = NameString::parse(processor_pkg.value()); + if (!name.has_value()) + return ParseResult::Failure; + + if (processor_pkg->size() < 1) + return ParseResult::Failure; + uint8_t id = processor_pkg.value()[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.value()[0]; + processor_pkg = processor_pkg->slice(1); + + auto processor = MUST(BAN::RefPtr::create(name->path.back(), id, pblk_addr, pblk_len)); + if (!context.root_namespace->add_named_object(context.scope.span(), name.value(), processor)) + return ParseResult::Failure; + + return processor->enter_context_and_parse_term_list(context, name.value(), processor_pkg.value()); + } + + virtual void debug_print(int indent) const override + { + AML_DEBUG_PRINT_INDENT(indent); + AML_DEBUG_PRINT("Processor "); + name.debug_print(); + AML_DEBUG_PRINT(" (ID: {}, PBlkAddr: 0x{H}, PBlkLen: {})", id, pblk_addr, pblk_len); + } + }; + +} diff --git a/kernel/include/kernel/ACPI/AML/Region.h b/kernel/include/kernel/ACPI/AML/Region.h new file mode 100644 index 00000000..bbe03186 --- /dev/null +++ b/kernel/include/kernel/ACPI/AML/Region.h @@ -0,0 +1,114 @@ +#pragma once + +#include +#include +#include + +namespace Kernel::ACPI::AML +{ + + struct OpRegion : public NamedObject + { + enum class RegionSpace + { + SystemMemory = 0, + SystemIO = 1, + PCIConfig = 2, + EmbeddedController = 3, + SMBus = 4, + SystemCMOS = 5, + PCIBarTarget = 6, + IPMI = 7, + GeneralPurposeIO = 8, + GenericSerialBus = 9, + PCC = 10, + }; + RegionSpace space; + uint64_t offset; + uint64_t length; + + OpRegion(NameSeg name, RegionSpace space, uint64_t offset, uint64_t length) + : NamedObject(Node::Type::OpRegion, name), space(space), offset(offset), length(length) + {} + + 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 = offset_result.node()->as_integer(); + if (!offset.has_value()) + { + 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 = length_result.node()->as_integer(); + if (!length.has_value()) + { + AML_ERROR("OpRegion length must be an integer"); + return ParseResult::Failure; + } + + auto op_region = MUST(BAN::RefPtr::create( + name->path.back(), + region_space, + offset.value(), + length.value() + )); + + if (!context.root_namespace->add_named_object(context.scope.span(), name.value(), op_region)) + return ParseResult::Failure; + +#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 (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::PCC: region_space_name = "PCC"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, offset, length); + } + + }; + +} diff --git a/kernel/include/kernel/ACPI/AML/Scope.h b/kernel/include/kernel/ACPI/AML/Scope.h new file mode 100644 index 00000000..aeeca7d9 --- /dev/null +++ b/kernel/include/kernel/ACPI/AML/Scope.h @@ -0,0 +1,25 @@ +#pragma once + +#include +#include +#include + +namespace Kernel::ACPI::AML +{ + + struct Scope : public AML::NamedObject + { + BAN::HashMap> objects; + + Scope(NameSeg name, Node::Type type = Node::Type::Scope) : NamedObject(type, name) {} + + virtual bool is_scope() const override { return true; } + + static ParseResult parse(ParseContext& context); + virtual void debug_print(int indent) const override; + + protected: + ParseResult enter_context_and_parse_term_list(ParseContext& outer_context, const AML::NameString& name, BAN::ConstByteSpan aml_data); + }; + +} diff --git a/kernel/include/kernel/ACPI/AML/String.h b/kernel/include/kernel/ACPI/AML/String.h new file mode 100644 index 00000000..2fbe62f5 --- /dev/null +++ b/kernel/include/kernel/ACPI/AML/String.h @@ -0,0 +1,51 @@ +#pragma once + +#include +#include +#include + +namespace Kernel::ACPI::AML +{ + + struct String : public AML::Node + { + BAN::String string; + + String() : Node(Node::Type::String) {} + + static ParseResult 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::String string; + + while (context.aml_data.size() > 0) + { + if (context.aml_data[0] == 0x00) + break; + MUST(string.push_back(static_cast(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); + } + + virtual void debug_print(int indent) const override + { + AML_DEBUG_PRINT_INDENT(indent); + AML_DEBUG_PRINT("String \"{}\"", string); + } + }; + +} diff --git a/kernel/include/kernel/ACPI/AML/TermObject.h b/kernel/include/kernel/ACPI/AML/TermObject.h deleted file mode 100644 index 89dff860..00000000 --- a/kernel/include/kernel/ACPI/AML/TermObject.h +++ /dev/null @@ -1,328 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include - -namespace Kernel::ACPI::AML -{ - // ACPI Spec 6.4, Section 20.2.5 - - struct TermObj; - struct TermArg; - - // TermList := Nothing | TermObj TermList - struct TermList - { - BAN::Vector terms; - - static bool can_parse(BAN::ConstByteSpan); - static BAN::Optional parse(BAN::ConstByteSpan&); - }; - - // MethodInvocation := NameString TermArgList - struct MethodInvocation - { - NameString name; - BAN::Vector term_args; - - static bool can_parse(BAN::ConstByteSpan); - static BAN::Optional parse(BAN::ConstByteSpan&); - }; - - // ExpressionOpcode := DefAcquire | DefAdd | DefAnd | DefBuffer | DefConcat | DefConcatRes | DefCondRefOf - // | DefCopyObject | DefDecrement | DefDerefOf | DefDivide | DefFindSetLeftBit - // | DefFindSetRightBit | DefFromBCD | DefIncrement | DefIndex | DefLAnd | DefLEqual - // | DefLGreater | DefLGreaterEqual | DefLLess | DefLLessEqual | DefMid | DefLNot - // | DefLNotEqual | DefLoadTable | DefLOr | DefMatch | DefMod | DefMultiply | DefNAnd - // | DefNOr | DefNot | DefObjectType | DefOr | DefPackage | DefVarPackage | DefRefOf - // | DefShiftLeft | DefShiftRight | DefSizeOf | DefStore | DefSubtract | DefTimer - // | DefToBCD | DefToBuffer | DefToDecimalString | DefToHexString | DefToInteger - // | DefToString | DefWait | DefXOr | MethodInvocation - struct ExpressionOpcode - { - struct UnaryOp - { - enum class Type - { - Decrement, - Increment, - RefOf, - SizeOf, - }; - Type type; - SuperName object; - }; - - struct BinaryOp - { - enum class Type - { - Add, - And, - Multiply, - NAnd, - NOr, - Or, - Subtract, - XOr, - ShiftLeft, - ShiftRight, - }; - Type type; - BAN::UniqPtr source1; - BAN::UniqPtr source2; - SuperName target; - }; - - struct LogicalBinaryOp - { - enum class Type - { - And, - Equal, - Greater, - Less, - Or, - // GreaterEqual, LessEqual, NotEqual handled by Not + LogicalBinaryOp - }; - Type type; - BAN::UniqPtr operand1; - BAN::UniqPtr operand2; - }; - -#define GEN_OPCODE_STRUCT_OPERAND_TARGET(NAME) struct NAME { BAN::UniqPtr operand; SuperName target; } - GEN_OPCODE_STRUCT_OPERAND_TARGET(ToBuffer); - GEN_OPCODE_STRUCT_OPERAND_TARGET(ToDecimalString); - GEN_OPCODE_STRUCT_OPERAND_TARGET(ToHexString); - GEN_OPCODE_STRUCT_OPERAND_TARGET(ToInteger); -#undef GEN_OPCODE_STRUCT_OPERAND_TARGET - - struct Acquire - { - SuperName mutex; - uint16_t timeout; - }; - struct Store - { - BAN::UniqPtr source; - SuperName target; - }; - - BAN::Variant< - UnaryOp, BinaryOp, LogicalBinaryOp, - ToBuffer, ToDecimalString, ToHexString, ToInteger, - Acquire, Buffer, Package, VarPackage, Store, MethodInvocation - > opcode; - - static bool can_parse(BAN::ConstByteSpan); - static BAN::Optional parse(BAN::ConstByteSpan&); - }; - - // TermArg := ExpressionOpcode | DataObject | ArgObj | LocalObj - struct TermArg - { - BAN::Variant arg; - - static bool can_parse(BAN::ConstByteSpan); - static BAN::Optional parse(BAN::ConstByteSpan&); - }; - - // NameSpaceModifierObj := DefAlias | DefName | DefScope - struct NameSpaceModifierObj - { - struct Alias {}; - struct Name - { - NameString name; - DataRefObject object; - }; - struct Scope - { - NameString name; - TermList term_list; - }; - BAN::Variant modifier; - - static bool can_parse(BAN::ConstByteSpan); - static BAN::Optional parse(BAN::ConstByteSpan&); - }; - - // NamedObj := DefBankField | DefCreateBitField | DefCreateByteField | DefCreateDWordField | DefCreateField - // | DefCreateQWordField | DefCreateWordField | DefDataRegion | DefExternal | DefOpRegion - // | DefProcessor(deprecated) | DefPowerRes | DefThermalZone - // Spec does not specify any of DefDevice, DefEvent, DefField, DefIndexField, DefMethod, DefMutex as options - struct NamedObj - { - struct CreateSizedField - { - enum class Type - { - Bit, - Byte, - Word, - DWord, - QWord, - }; - Type type; - TermArg buffer; - TermArg index; - NameString name; - }; - - struct BankField {}; - struct CreateField {}; - struct DataRegion {}; - struct External {}; - struct OpRegion - { - enum class RegionSpace : uint8_t - { - SystemMemory = 0x00, - SystemIO = 0x01, - PCIConfigSpace = 0x02, - EmbeddedController = 0x03, - SMBus = 0x04, - SystemCMOS = 0x05, - PCIBarTarget = 0x06, - IPMI = 0x07, - GeneralPurposeIO = 0x08, - ResourceDescriptor = 0x09, - PCC = 0x0A, - }; - - NameString name; - RegionSpace region_space; - TermArg region_offset; - TermArg region_length; - }; - struct Processor - { - NameString name; - uint8_t processor_id; - uint32_t p_blk_address; - uint8_t p_blk_length; - TermList term_list; - }; - struct PowerRes {}; - struct ThermalZone {}; - struct Device - { - NameString name; - TermList term_list; - }; - struct Event {}; - struct Field - { - NameString name; - // field flags - // field list - }; - struct IndexField {}; - struct Method - { - NameString name; - uint8_t argument_count; - bool serialized; - uint8_t sync_level; - TermList term_list; - }; - struct Mutex - { - NameString name; - uint8_t sync_level; - }; - - BAN::Variant object; - - static bool can_parse(BAN::ConstByteSpan); - static BAN::Optional parse(BAN::ConstByteSpan&); - }; - - // Object := NameSpaceModifierObj | NamedObj - struct Object - { - BAN::Variant object; - - static bool can_parse(BAN::ConstByteSpan); - static BAN::Optional parse(BAN::ConstByteSpan&); - }; - - // StatementOpcode := DefBreak | DefBreakPoint | DefContinue | DefFatal | DefIfElse | DefNoop | DefNotify - // | DefRelease | DefReset | DefReturn | DefSignal | DefSleep | DefStall | DefWhile - struct StatementOpcode - { - struct IfElse - { - TermArg predicate; - TermList true_list; - TermList false_list; - }; - struct Notify - { - SuperName object; - TermArg value; - }; - struct Release - { - SuperName mutex; - }; - struct Return - { - // TODO: Is argument actually optional? - // This is not specified in the spec but it seems like it should be - BAN::Optional arg; - }; - - BAN::Variant opcode; - - static bool can_parse(BAN::ConstByteSpan); - static BAN::Optional parse(BAN::ConstByteSpan&); - }; - - // TermObj := Object | StatementOpcode | ExpressionOpcode - struct TermObj - { - BAN::Variant term; - - static bool can_parse(BAN::ConstByteSpan); - static BAN::Optional parse(BAN::ConstByteSpan&); - }; - - // ReferenceTypeOpcode := DefRefOf | DefDerefOf | DefIndex | UserTermObj - struct ReferenceTypeOpcode - { - struct RefOf - { - SuperName target; - }; - struct DerefOf - { - TermArg source; - }; - struct Index - { - TermArg source; - TermArg index; - SuperName destination; - }; - struct UserTermObj - { - MethodInvocation method; - }; - - BAN::Variant opcode; - - static bool can_parse(BAN::ConstByteSpan); - static BAN::Optional parse(BAN::ConstByteSpan&); - }; - -} diff --git a/kernel/include/kernel/ACPI/AML/Utils.h b/kernel/include/kernel/ACPI/AML/Utils.h new file mode 100644 index 00000000..280efcbb --- /dev/null +++ b/kernel/include/kernel/ACPI/AML/Utils.h @@ -0,0 +1,36 @@ +#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/kernel/ACPI/ACPI.cpp b/kernel/kernel/ACPI/ACPI.cpp index 721f4101..355c9e7a 100644 --- a/kernel/kernel/ACPI/ACPI.cpp +++ b/kernel/kernel/ACPI/ACPI.cpp @@ -35,7 +35,7 @@ namespace Kernel::ACPI auto dsdt = s_instance->get_header("DSDT", 0); ASSERT(dsdt); - AMLParser::parse_table(*dsdt); + s_instance->m_namespace = AMLParser::parse_table(*dsdt); #if ARCH(x86_64) lai_create_namespace(); diff --git a/kernel/kernel/ACPI/AML.cpp b/kernel/kernel/ACPI/AML.cpp index a9c58a9a..a70d4736 100644 --- a/kernel/kernel/ACPI/AML.cpp +++ b/kernel/kernel/ACPI/AML.cpp @@ -3,33 +3,34 @@ #include #include -#include - -namespace Kernel::ACPI::AML { size_t g_depth = 0; } - namespace Kernel::ACPI { AMLParser::AMLParser() = default; AMLParser::~AMLParser() = default; - AMLParser AMLParser::parse_table(const SDTHeader& header) + BAN::RefPtr AMLParser::parse_table(const SDTHeader& header) { - dprintln("Parsing {}, {} bytes of AML", header, header.length - sizeof(header)); + dprintln("Parsing {}, {} bytes of AML", header, header.length); auto aml_raw = BAN::ConstByteSpan { reinterpret_cast(&header), header.length }; aml_raw = aml_raw.slice(sizeof(header)); - if (!AML::TermList::can_parse(aml_raw)) - dwarnln("Can not AML term_list"); - else + auto ns = AML::Namespace::parse(aml_raw); + if (!ns) { - auto term_list = AML::TermList::parse(aml_raw); - if (!term_list.has_value()) - dwarnln("Failed to parse AML term_list"); + dwarnln("Failed to parse ACPI namespace"); + return {}; } - return {}; +#if AML_DEBUG_LEVEL >= 1 + ns->debug_print(0); + AML_DEBUG_PRINTLN(""); +#endif + + dprintln("Parsed ACPI namespace"); + + return ns; } } diff --git a/kernel/kernel/ACPI/AML/DataObject.cpp b/kernel/kernel/ACPI/AML/DataObject.cpp deleted file mode 100644 index b4a032b8..00000000 --- a/kernel/kernel/ACPI/AML/DataObject.cpp +++ /dev/null @@ -1,278 +0,0 @@ -#include -#include -#include - -namespace Kernel::ACPI -{ - - // Integer - - bool AML::Integer::can_parse(BAN::ConstByteSpan span) - { - if (span.size() < 1) - return false; - switch (static_cast(span[0])) - { - case AML::Byte::BytePrefix: - case AML::Byte::WordPrefix: - case AML::Byte::DWordPrefix: - case AML::Byte::QWordPrefix: - return true; - default: - return false; - } - } - - BAN::Optional AML::Integer::parse(BAN::ConstByteSpan& span) - { - AML_DEBUG_PRINT_FN(); - ASSERT(can_parse(span)); - - switch (static_cast(span[0])) - { -#define AML_PARSE_INTEGER_CASE(TYPE, BYTES) \ - case AML::Byte::TYPE##Prefix: \ - { \ - span = span.slice(1); \ - if (span.size() < BYTES) \ - { \ - AML_DEBUG_CANNOT_PARSE(#TYPE, span); \ - return {}; \ - } \ - uint64_t value = 0; \ - for (size_t i = 0; i < BYTES; i++) \ - value |= static_cast(span[i]) << (i * 8); \ - AML_DEBUG_PRINT("0x{H}", value); \ - span = span.slice(BYTES); \ - return Integer { .value = value }; \ - } - AML_PARSE_INTEGER_CASE(Byte, 1) - AML_PARSE_INTEGER_CASE(Word, 2) - AML_PARSE_INTEGER_CASE(DWord, 4) - AML_PARSE_INTEGER_CASE(QWord, 8) -#undef AML_PARSE_INTEGER_CASE - default: - ASSERT_NOT_REACHED(); - } - } - - - // Buffer - - bool AML::Buffer::can_parse(BAN::ConstByteSpan span) - { - if (span.size() < 1) - return false; - if (static_cast(span[0]) == AML::Byte::BufferOp) - return true; - return false; - } - - BAN::Optional AML::Buffer::parse(BAN::ConstByteSpan& span) - { - AML_DEBUG_PRINT_FN(); - ASSERT(can_parse(span)); - - span = span.slice(1); - - AML_TRY_PARSE_PACKAGE(buffer_span); - - AML_TRY_PARSE(buffer_size, AML::Integer, buffer_span); - - BAN::Vector data; - MUST(data.resize(BAN::Math::max(buffer_size->value, buffer_span.size()))); - for (size_t i = 0; i < buffer_span.size(); i++) - data[i] = buffer_span[i]; - - return Buffer { .buffer_size = buffer_size.release_value(), .data = BAN::move(data) }; - } - - - // ComputationalData - - bool AML::ComputationalData::can_parse(BAN::ConstByteSpan span) - { - if (span.size() < 1) - return false; - if (static_cast(span[0]) == AML::Byte::ExtOpPrefix) - { - if (span.size() < 2) - return false; - switch (static_cast(span[1])) - { - case AML::Byte::ExtRevisionOp: - return true; - default: - return false; - } - } - switch (static_cast(span[0])) - { - case AML::Byte::ZeroOp: - case AML::Byte::OneOp: - case AML::Byte::OnesOp: - case AML::Byte::BytePrefix: - case AML::Byte::WordPrefix: - case AML::Byte::DWordPrefix: - case AML::Byte::StringPrefix: - case AML::Byte::QWordPrefix: - case AML::Byte::BufferOp: - return true; - default: - return false; - } - } - - BAN::Optional AML::ComputationalData::parse(BAN::ConstByteSpan& span) - { - AML_DEBUG_PRINT_FN(); - ASSERT(can_parse(span)); - - AML_TRY_PARSE_IF_CAN(AML::Buffer); - AML_TRY_PARSE_IF_CAN(AML::Integer); - - switch (static_cast(span[0])) - { -#define AML_PARSE_CONST(TYPE) \ - case AML::Byte::TYPE##Op: \ - { \ - span = span.slice(1); \ - AML_DEBUG_PRINT("{}", #TYPE); \ - return ConstObj { .type = ConstObj::Type::TYPE }; \ - } - AML_PARSE_CONST(Zero); - AML_PARSE_CONST(One); - AML_PARSE_CONST(Ones); -#undef AML_PARSE_CONST - case AML::Byte::StringPrefix: - { - span = span.slice(1); - - BAN::String value; - while (span.size() > 0) - { - if (span[0] == 0x00 || span[0] > 0x7F) - break; - MUST(value.push_back(span[0])); - span = span.slice(1); - } - - if (span.size() == 0 || span[0] != 0x00) - return {}; - span = span.slice(1); - - AML_DEBUG_PRINT("\"{}\"", value); - return String { .value = BAN::move(value) }; - } - GEN_PARSE_CASE_TODO(BufferOp) - default: - ASSERT_NOT_REACHED(); - } - - ASSERT_NOT_REACHED(); - } - - -#define AML_GEN_PACKAGE(NAME) \ - bool AML::NAME::can_parse(BAN::ConstByteSpan span) \ - { \ - if (span.size() < 1) \ - return false; \ - if (static_cast(span[0]) == AML::Byte::NAME##Op) \ - return true; \ - return false; \ - } \ - \ - BAN::Optional AML::NAME::parse(BAN::ConstByteSpan& span) \ - { \ - AML_DEBUG_PRINT_FN(); \ - ASSERT(can_parse(span)); \ - \ - span = span.slice(1); \ - \ - AML_TRY_PARSE_PACKAGE(package_span); \ - \ - uint8_t count = package_span[0]; \ - package_span = package_span.slice(1); \ - \ - AML_DEBUG_PRINT("Count: {}", count); \ - \ - BAN::Vector elements; \ - for (uint8_t i = 0; package_span.size() > 0 && i < count; i++) \ - { \ - if (DataRefObject::can_parse(package_span)) \ - { \ - AML_TRY_PARSE(element, DataRefObject, package_span); \ - MUST(elements.push_back(PackageElement { \ - MUST(BAN::UniqPtr::create(element.release_value())) \ - })); \ - } \ - else if (NameString::can_parse(package_span)) \ - { \ - AML_TRY_PARSE(element, NameString, package_span); \ - MUST(elements.push_back(PackageElement { \ - element.release_value() \ - })); \ - } \ - else \ - { \ - AML_DEBUG_CANNOT_PARSE("PackageElement", package_span); \ - return {}; \ - } \ - } \ - \ - while (elements.size() < count) \ - MUST(elements.push_back(PackageElement { Uninitialized {} })); \ - \ - return NAME { .elements = BAN::move(elements) }; \ - } - - AML_GEN_PACKAGE(Package) - AML_GEN_PACKAGE(VarPackage) -#undef AML_GEN_PACKAGE - - // DataObject - - bool AML::DataObject::can_parse(BAN::ConstByteSpan span) - { - if (ComputationalData::can_parse(span)) - return true; - if (Package::can_parse(span)) - return true; - if (VarPackage::can_parse(span)) - return true; - return false; - } - - BAN::Optional AML::DataObject::parse(BAN::ConstByteSpan& span) - { - AML_DEBUG_PRINT_FN(); - ASSERT(can_parse(span)); - AML_TRY_PARSE_IF_CAN(ComputationalData); - AML_TRY_PARSE_IF_CAN(Package); - AML_TRY_PARSE_IF_CAN(VarPackage); - ASSERT_NOT_REACHED(); - } - - - // DataRefObject - - bool AML::DataRefObject::can_parse(BAN::ConstByteSpan span) - { - if (DataObject::can_parse(span)) - return true; - if (Integer::can_parse(span)) - return true; - return false; - } - - BAN::Optional AML::DataRefObject::parse(BAN::ConstByteSpan& span) - { - AML_DEBUG_PRINT_FN(); - ASSERT(can_parse(span)); - AML_TRY_PARSE_IF_CAN(DataObject); - AML_TRY_PARSE_IF_CAN(Integer); - ASSERT_NOT_REACHED(); - } - -} diff --git a/kernel/kernel/ACPI/AML/Field.cpp b/kernel/kernel/ACPI/AML/Field.cpp new file mode 100644 index 00000000..d525ecaf --- /dev/null +++ b/kernel/kernel/ACPI/AML/Field.cpp @@ -0,0 +1,224 @@ +#include + +namespace Kernel::ACPI +{ + + 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) + { + 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: + case 0x02: + case 0x03: + AML_TODO("Field element {2H}", context.field_pkg[0]); + return false; + 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; + } + } + } + + 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 = context.root_namespace->find_object(context.scope.span(), name_string.value()); + if (!op_region || op_region->type != AML::Node::Type::OpRegion) + { + AML_ERROR("Field RegionName does not name a valid OpRegion"); + 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 (!context.root_namespace->add_named_object(context.scope.span(), element_name, element)) + return ParseResult::Failure; + +#if AML_DEBUG_LEVEL >= 2 + element->debug_print(0); + AML_DEBUG_PRINTLN(""); +#endif + } + + return ParseResult::Success; + } + + void AML::FieldElement::debug_print(int indent) const + { + AML_DEBUG_PRINT_INDENT(indent); + AML_DEBUG_PRINT("FieldElement "); + name.debug_print(); + AML_DEBUG_PRINT("({}, offset {}, OpRegion ", bit_count, bit_offset); + op_region->name.debug_print(); + AML_DEBUG_PRINT(")"); + } + + 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 = context.root_namespace->find_object(context.scope.span(), index_field_element_name.value()); + 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 = context.root_namespace->find_object(context.scope.span(), data_field_element_name.value()); + 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 (!context.root_namespace->add_named_object(context.scope.span(), element_name, element)) + return ParseResult::Failure; + +#if AML_DEBUG_LEVEL >= 2 + element->debug_print(0); + AML_DEBUG_PRINTLN(""); +#endif + } + + return AML::ParseResult::Success; + } + + void AML::IndexFieldElement::debug_print(int indent) const + { + AML_DEBUG_PRINT_INDENT(indent); + AML_DEBUG_PRINT("IndexFieldElement "); + name.debug_print(); + AML_DEBUG_PRINT("({}, offset {}, IndexName ", bit_count, bit_offset); + index_element->name.debug_print(); + AML_DEBUG_PRINT(", DataName "); + data_element->name.debug_print(); + AML_DEBUG_PRINT(")"); + } + +} diff --git a/kernel/kernel/ACPI/AML/MiscObject.cpp b/kernel/kernel/ACPI/AML/MiscObject.cpp deleted file mode 100644 index 7722cea9..00000000 --- a/kernel/kernel/ACPI/AML/MiscObject.cpp +++ /dev/null @@ -1,99 +0,0 @@ -#include -#include - -namespace Kernel::ACPI -{ - - // ArgObj - - bool AML::ArgObj::can_parse(BAN::ConstByteSpan span) - { - if (span.size() < 1) - return false; - switch (static_cast(span[0])) - { - case AML::Byte::Arg0Op: - case AML::Byte::Arg1Op: - case AML::Byte::Arg2Op: - case AML::Byte::Arg3Op: - case AML::Byte::Arg4Op: - case AML::Byte::Arg5Op: - case AML::Byte::Arg6Op: - return true; - default: - return false; - } - } - - BAN::Optional AML::ArgObj::parse(BAN::ConstByteSpan& span) - { - AML_DEBUG_PRINT_FN(); - ASSERT(can_parse(span)); - - uint8_t type = static_cast(span[0]) - static_cast(AML::Byte::Arg0Op); - span = span.slice(1); - - AML_DEBUG_PRINT("Arg{}", type); - - return ArgObj { .type = static_cast(type) }; - } - - - // LocalObj - - bool AML::LocalObj::can_parse(BAN::ConstByteSpan span) - { - if (span.size() < 1) - return false; - switch (static_cast(span[0])) - { - case AML::Byte::Local0Op: - case AML::Byte::Local1Op: - case AML::Byte::Local2Op: - case AML::Byte::Local3Op: - case AML::Byte::Local4Op: - case AML::Byte::Local5Op: - case AML::Byte::Local6Op: - case AML::Byte::Local7Op: - return true; - default: - return false; - } - } - - BAN::Optional AML::LocalObj::parse(BAN::ConstByteSpan& span) - { - AML_DEBUG_PRINT_FN(); - ASSERT(can_parse(span)); - - uint8_t type = static_cast(span[0]) - static_cast(AML::Byte::Local0Op); - span = span.slice(1); - - AML_DEBUG_PRINT("Local{}", type); - - return LocalObj { .type = static_cast(type) }; - } - - // DebugObj - - bool AML::DebugObj::can_parse(BAN::ConstByteSpan span) - { - if (span.size() < 2) - return false; - if (static_cast(span[0]) != AML::Byte::ExtOpPrefix) - return false; - if (static_cast(span[1]) != AML::Byte::ExtDebugOp) - return false; - return true; - } - - BAN::Optional AML::DebugObj::parse(BAN::ConstByteSpan& span) - { - AML_DEBUG_PRINT_FN(); - ASSERT(can_parse(span)); - - span = span.slice(2); - return DebugObj {}; - } - -} diff --git a/kernel/kernel/ACPI/AML/NameObject.cpp b/kernel/kernel/ACPI/AML/NameObject.cpp deleted file mode 100644 index f4ff270a..00000000 --- a/kernel/kernel/ACPI/AML/NameObject.cpp +++ /dev/null @@ -1,162 +0,0 @@ -#include -#include -#include - -namespace Kernel::ACPI -{ - - static constexpr bool is_lead_name_char(uint8_t ch) - { - return ('A' <= ch && ch <= 'Z') || ch == '_'; - } - - static constexpr bool is_name_char(uint8_t ch) - { - return is_lead_name_char(ch) || ('0' <= ch && ch <= '9'); - } - - - // NameString - - bool AML::NameString::can_parse(BAN::ConstByteSpan span) - { - if (span.size() < 1) - return false; - if (span[0] == '\\' || span[0] == '^' || span[0] == 0x00) - return true; - if (static_cast(span[0]) == AML::Byte::DualNamePrefix) - return true; - if (static_cast(span[0]) == AML::Byte::MultiNamePrefix) - return true; - if (is_lead_name_char(span[0])) - return true; - return false; - } - - BAN::Optional AML::NameString::parse(BAN::ConstByteSpan& span) - { - AML_DEBUG_PRINT_FN(); - ASSERT(can_parse(span)); - - NameString name_string; - - if (span[0] == '\\') - { - MUST(name_string.prefix.push_back('\\')); - span = span.slice(1); - } - else if (span[0] == '^') - { - while (span[0] == '^') - { - MUST(name_string.prefix.push_back('^')); - span = span.slice(1); - } - } - - size_t name_count = 1; - switch (span[0]) - { - case 0x00: - name_count = 0; - span = span.slice(1); - break; - case static_cast(AML::Byte::DualNamePrefix): - name_count = 2; - span = span.slice(1); - break; - case static_cast(AML::Byte::MultiNamePrefix): - name_count = span[1]; - span = span.slice(2); - break; - } - - if (span.size() < name_count * 4) - return {}; - - MUST(name_string.path.resize(name_count)); - - for (size_t i = 0; i < name_count; i++) - { - if (!is_lead_name_char(span[0]) || !is_name_char(span[1]) || !is_name_char(span[2]) || !is_name_char(span[3])) - { - AML_DEBUG_ERROR("Invalid NameSeg {2H} {2H} {2H} {2H}", span[0], span[1], span[2], span[3]); - ASSERT_NOT_REACHED(); - return {}; - } - MUST(name_string.path[i].append(BAN::StringView(reinterpret_cast(span.data()), 4))); - while (name_string.path[i].back() == '_') - name_string.path[i].pop_back(); - span = span.slice(4); - } - - if constexpr(DUMP_AML) - { - BAN::String full_string; - MUST(full_string.append(name_string.prefix)); - for (size_t i = 0; i < name_string.path.size(); i++) - { - if (i != 0) - MUST(full_string.push_back('.')); - MUST(full_string.append(name_string.path[i])); - } - AML_DEBUG_PRINT("'{}'", full_string); - } - - return name_string; - } - - - // SimpleName - - bool AML::SimpleName::can_parse(BAN::ConstByteSpan span) - { - if (NameString::can_parse(span)) - return true; - if (ArgObj::can_parse(span)) - return true; - if (LocalObj::can_parse(span)) - return true; - return false; - } - - BAN::Optional AML::SimpleName::parse(BAN::ConstByteSpan& span) - { - AML_DEBUG_PRINT_FN(); - ASSERT(can_parse(span)); - AML_TRY_PARSE_IF_CAN(NameString); - AML_TRY_PARSE_IF_CAN(ArgObj); - AML_TRY_PARSE_IF_CAN(LocalObj); - ASSERT_NOT_REACHED(); - } - - - // SuperName - - bool AML::SuperName::can_parse(BAN::ConstByteSpan span) - { - if (SimpleName::can_parse(span)) - return true; - if (DebugObj::can_parse(span)) - return true; - if (ReferenceTypeOpcode::can_parse(span)) - return true; - return false; - } - - BAN::Optional AML::SuperName::parse(BAN::ConstByteSpan& span) - { - AML_DEBUG_PRINT_FN(); - ASSERT(can_parse(span)); - - AML_TRY_PARSE_IF_CAN(SimpleName); - AML_TRY_PARSE_IF_CAN(DebugObj); - - ASSERT(ReferenceTypeOpcode::can_parse(span)); - auto opcode = ReferenceTypeOpcode::parse(span); - if (!opcode.has_value()) - return {}; - return SuperName { .name = MUST(BAN::UniqPtr::create(opcode.release_value())) }; - } - -} diff --git a/kernel/kernel/ACPI/AML/NamedObject.cpp b/kernel/kernel/ACPI/AML/NamedObject.cpp new file mode 100644 index 00000000..7779909c --- /dev/null +++ b/kernel/kernel/ACPI/AML/NamedObject.cpp @@ -0,0 +1,45 @@ +#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 (!context.root_namespace->add_named_object(context.scope.span(), name_string.value(), name)) + return ParseResult::Failure; + +#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_PRINT("Name "); + name.debug_print(); + AML_DEBUG_PRINTLN(" {"); + 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 new file mode 100644 index 00000000..93d48dba --- /dev/null +++ b/kernel/kernel/ACPI/AML/Namespace.cpp @@ -0,0 +1,123 @@ +#include +#include +#include + +namespace Kernel::ACPI +{ + + BAN::Optional> AML::Namespace::resolve_path(BAN::Span parsing_scope, const AML::NameString& relative_path) + { + BAN::Vector canonical_path; + + if (!relative_path.prefix.empty()) + { + if (relative_path.prefix[0] == '\\') + ; + else + { + if (parsing_scope.size() < relative_path.prefix.size()) + { + AML_ERROR("Trying to resolve parent of root object"); + return {}; + } + for (size_t i = 0; i < parsing_scope.size() - relative_path.prefix.size(); i++) + MUST(canonical_path.push_back(parsing_scope[i])); + } + } + else + { + for (auto seg : parsing_scope) + MUST(canonical_path.push_back(seg)); + } + + for (const auto& seg : relative_path.path) + MUST(canonical_path.push_back(seg)); + + return canonical_path; + } + + BAN::RefPtr AML::Namespace::find_object(BAN::Span parsing_scope, const AML::NameString& relative_path) + { + auto canonical_path = resolve_path(parsing_scope, relative_path); + if (!canonical_path.has_value()) + return nullptr; + if (canonical_path->empty()) + return this; + + BAN::RefPtr parent_object = this; + + for (const auto& seg : canonical_path.value()) + { + if (!parent_object->is_scope()) + { + AML_ERROR("Parent object is not a scope"); + return nullptr; + } + + auto* parent_scope = static_cast(parent_object.ptr()); + + auto it = parent_scope->objects.find(seg); + if (it == parent_scope->objects.end()) + return nullptr; + + parent_object = it->value; + ASSERT(parent_object); + } + + return parent_object; + } + + bool AML::Namespace::add_named_object(BAN::Span parsing_scope, const AML::NameString& object_path, BAN::RefPtr object) + { + ASSERT(!object_path.path.empty()); + ASSERT(object_path.path.back() == object->name); + + auto parent_path = object_path; + parent_path.path.pop_back(); + + auto parent_object = find_object(parsing_scope, parent_path); + if (!parent_object) + { + AML_ERROR("Parent object not found"); + return false; + } + + if (!parent_object->is_scope()) + { + AML_ERROR("Parent object is not a scope"); + return false; + } + + auto* parent_scope = static_cast(parent_object.ptr()); + if (parent_scope->objects.contains(object->name)) + { + AML_ERROR("Object already exists"); + return false; + } + + MUST(parent_scope->objects.insert(object->name, object)); + return true; + } + + BAN::RefPtr AML::Namespace::parse(BAN::ConstByteSpan aml_data) + { + auto result = MUST(BAN::RefPtr::create()); + + AML::ParseContext context; + context.aml_data = aml_data; + context.root_namespace = result.ptr(); + + while (context.aml_data.size() > 0) + { + auto result = AML::parse_object(context); + if (!result.success()) + { + AML_ERROR("Failed to parse object"); + return {}; + } + } + + return result; + } + +} diff --git a/kernel/kernel/ACPI/AML/Node.cpp b/kernel/kernel/ACPI/AML/Node.cpp new file mode 100644 index 00000000..ecbade89 --- /dev/null +++ b/kernel/kernel/ACPI/AML/Node.cpp @@ -0,0 +1,102 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Kernel::ACPI +{ + + AML::ParseResult AML::ParseResult::Failure = AML::ParseResult(AML::ParseResult::Result::Failure); + AML::ParseResult AML::ParseResult::Success = AML::ParseResult(AML::ParseResult::Result::Success); + + AML::ParseResult AML::parse_object(AML::ParseContext& context) + { + if (context.aml_data.size() < 1) + return ParseResult::Failure; + + if (static_cast(context.aml_data[0]) == AML::Byte::ExtOpPrefix) + { + if (context.aml_data.size() < 2) + return ParseResult::Failure; + + switch (static_cast(context.aml_data[1])) + { + case AML::ExtOp::FieldOp: + return AML::Field::parse(context); + case AML::ExtOp::IndexFieldOp: + return AML::IndexField::parse(context); + case AML::ExtOp::OpRegionOp: + return AML::OpRegion::parse(context); + case AML::ExtOp::DeviceOp: + return AML::Device::parse(context); + case AML::ExtOp::MutexOp: + return AML::Mutex::parse(context); + case AML::ExtOp::ProcessorOp: + return AML::Processor::parse(context); + default: + break; + } + + AML_TODO("{2H} {2H}", context.aml_data[0], context.aml_data[1]); + return ParseResult::Failure; + } + + switch (static_cast(context.aml_data[0])) + { + case AML::Byte::ZeroOp: + case AML::Byte::OneOp: + case AML::Byte::OnesOp: + case AML::Byte::BytePrefix: + case AML::Byte::WordPrefix: + case AML::Byte::DWordPrefix: + case AML::Byte::QWordPrefix: + return AML::Integer::parse(context.aml_data); + case AML::Byte::StringPrefix: + return AML::String::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); + 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])) + { + auto name_string = AML::NameString::parse(context.aml_data); + if (!name_string.has_value()) + return ParseResult::Failure; + auto aml_object = context.root_namespace->find_object(context.scope.span(), name_string.value()); + if (!aml_object) + { + AML_TODO("NameString not found in namespace"); + return ParseResult::Failure; + } + return ParseResult(aml_object); + } + + AML_TODO("{2H}", context.aml_data[0]); + return ParseResult::Failure; + } + +} diff --git a/kernel/kernel/ACPI/AML/Scope.cpp b/kernel/kernel/ACPI/AML/Scope.cpp new file mode 100644 index 00000000..db8ff441 --- /dev/null +++ b/kernel/kernel/ACPI/AML/Scope.cpp @@ -0,0 +1,77 @@ +#include +#include +#include +#include + +namespace Kernel::ACPI +{ + + AML::ParseResult AML::Scope::parse(ParseContext& context) + { + 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; + + BAN::RefPtr scope; + if (auto named_object = context.root_namespace->find_object(context.scope.span(), name_string.value())) + { + if (!named_object->is_scope()) + { + AML_ERROR("Scope name already exists and is not a scope"); + return ParseResult::Failure; + } + scope = static_cast(named_object.ptr()); + } + else + { + scope = MUST(BAN::RefPtr::create(name_string->path.back())); + if (!context.root_namespace->add_named_object(context.scope.span(), name_string.value(), scope)) + return ParseResult::Failure; + } + + 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 scope = outer_context.root_namespace->resolve_path(outer_context.scope.span(), name_string); + if (!scope.has_value()) + return ParseResult::Failure; + + ParseContext scope_context = outer_context; + scope_context.scope = scope.release_value(); + scope_context.aml_data = aml_data; + while (scope_context.aml_data.size() > 0) + { + auto object_result = AML::parse_object(scope_context); + if (!object_result.success()) + return ParseResult::Failure; + } + + return ParseResult::Success; + } + + void AML::Scope::debug_print(int indent) const + { + AML_DEBUG_PRINT_INDENT(indent); + AML_DEBUG_PRINT("Scope "); + name.debug_print(); + AML_DEBUG_PRINTLN(" {"); + for (const auto& [name, object] : objects) + { + object->debug_print(indent + 1); + AML_DEBUG_PRINTLN(""); + } + AML_DEBUG_PRINT_INDENT(indent); + AML_DEBUG_PRINT("}"); + } + +} diff --git a/kernel/kernel/ACPI/AML/TermObject.cpp b/kernel/kernel/ACPI/AML/TermObject.cpp deleted file mode 100644 index 629d3e4b..00000000 --- a/kernel/kernel/ACPI/AML/TermObject.cpp +++ /dev/null @@ -1,1031 +0,0 @@ -#include -#include -#include - -namespace Kernel::ACPI -{ - - // NameSpaceModifierObj - - bool AML::NameSpaceModifierObj::can_parse(BAN::ConstByteSpan span) - { - if (span.size() < 1) - return false; - switch (static_cast(span[0])) - { - case AML::Byte::AliasOp: - case AML::Byte::NameOp: - case AML::Byte::ScopeOp: - return true; - default: - return false; - } - } - - BAN::Optional AML::NameSpaceModifierObj::parse(BAN::ConstByteSpan& span) - { - AML_DEBUG_PRINT_FN(); - ASSERT(can_parse(span)); - - switch (static_cast(span[0])) - { - case AML::Byte::NameOp: - { - span = span.slice(1); - - AML_DEBUG_PRINT("Name"); - AML_DEBUG_INDENT_SCOPE(); - - AML_TRY_PARSE(name, AML::NameString, span); - AML_TRY_PARSE(object, AML::DataRefObject, span); - - return AML::NameSpaceModifierObj { - .modifier = AML::NameSpaceModifierObj::Name { - .name = name.release_value(), - .object = object.release_value() - } - }; - } - case AML::Byte::ScopeOp: - { - span = span.slice(1); - - AML_DEBUG_PRINT("Scope"); - AML_DEBUG_INDENT_SCOPE(); - - AML_TRY_PARSE_PACKAGE(scope_span); - AML_TRY_PARSE(name, AML::NameString, scope_span); - AML_TRY_PARSE(term_list, AML::TermList, scope_span); - - return AML::NameSpaceModifierObj { - .modifier = AML::NameSpaceModifierObj::Scope { - .name = name.release_value(), - .term_list = term_list.release_value() - } - }; - } - GEN_PARSE_CASE_TODO(AliasOp) - default: - ASSERT_NOT_REACHED(); - } - } - - - // NamedObj - - bool AML::NamedObj::can_parse(BAN::ConstByteSpan span) - { - if (span.size() < 1) - return false; - if (static_cast(span[0]) == AML::Byte::ExtOpPrefix) - { - if (span.size() < 2) - return false; - switch (static_cast(span[1])) - { - case AML::Byte::ExtCreateFieldOp: - case AML::Byte::ExtOpRegionOp: - case AML::Byte::ExtPowerResOp: - case AML::Byte::ExtProcessorOp: - case AML::Byte::ExtThermalZoneOp: - case AML::Byte::ExtBankFieldOp: - case AML::Byte::ExtDataRegionOp: - case AML::Byte::ExtMutexOp: - case AML::Byte::ExtEventOp: - case AML::Byte::ExtFieldOp: - case AML::Byte::ExtDeviceOp: - case AML::Byte::ExtIndexFieldOp: - return true; - default: - return false; - } - } - switch (static_cast(span[0])) - { - case AML::Byte::ExternalOp: - case AML::Byte::CreateDWordFieldOp: - case AML::Byte::CreateWordFieldOp: - case AML::Byte::CreateByteFieldOp: - case AML::Byte::CreateBitFieldOp: - case AML::Byte::CreateQWordFieldOp: - case AML::Byte::MethodOp: - return true; - default: - return false; - } - } - -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wstack-usage=" - BAN::Optional AML::NamedObj::parse(BAN::ConstByteSpan& span) - { - AML_DEBUG_PRINT_FN(); - ASSERT(can_parse(span)); - - if (static_cast(span[0]) == AML::Byte::ExtOpPrefix) - { - switch (static_cast(span[1])) - { - case AML::Byte::ExtOpRegionOp: - { - span = span.slice(2); - - AML_DEBUG_PRINT("OpRegion"); - AML_DEBUG_INDENT_SCOPE(); - - AML_TRY_PARSE(name_string, AML::NameString, span); - - auto region_space = static_cast(span[0]); - span = span.slice(1); - - AML_DEBUG_PRINT("RegionSpace"); - { - AML_DEBUG_INDENT_SCOPE(); - AML_DEBUG_PRINT("0x{2H}", static_cast(region_space)); - } - - AML_TRY_PARSE(region_offset, AML::TermArg, span); - AML_TRY_PARSE(region_length, AML::TermArg, span); - - return AML::NamedObj { - .object = AML::NamedObj::OpRegion { - .name = name_string.release_value(), - .region_space = region_space, - .region_offset = region_offset.release_value(), - .region_length = region_length.release_value() - } - }; - } - case AML::Byte::ExtFieldOp: - { - span = span.slice(2); - - AML_DEBUG_PRINT("Field"); - AML_DEBUG_INDENT_SCOPE(); - - AML_TRY_PARSE_PACKAGE(field_span); - AML_TRY_PARSE(name_string, AML::NameString, field_span); - //AML_DEBUG_TODO("FieldFlags"); - //AML_DEBUG_TODO("FieldList"); - - return AML::NamedObj { - .object = AML::NamedObj::Field { - .name = name_string.release_value() - } - }; - } - case AML::Byte::ExtDeviceOp: - { - span = span.slice(2); - - AML_DEBUG_PRINT("Device"); - AML_DEBUG_INDENT_SCOPE(); - - AML_TRY_PARSE_PACKAGE(device_span); - AML_TRY_PARSE(name_string, AML::NameString, device_span); - AML_TRY_PARSE(term_list, AML::TermList, device_span); - - return AML::NamedObj { - .object = AML::NamedObj::Device { - .name = name_string.release_value(), - .term_list = term_list.release_value() - } - }; - } - case AML::Byte::ExtProcessorOp: - { - span = span.slice(2); - - AML_DEBUG_PRINT("Processor"); - AML_DEBUG_INDENT_SCOPE(); - - AML_TRY_PARSE_PACKAGE(processor_span); - AML_TRY_PARSE(name_string, AML::NameString, processor_span); - - auto processor_id = processor_span[0]; - processor_span = processor_span.slice(1); - AML_DEBUG_PRINT("ProcessorId"); - { - AML_DEBUG_INDENT_SCOPE(); - AML_DEBUG_PRINT("0x{2H}", processor_id); - } - - uint32_t p_blk_address = processor_span[0] | (processor_span[1] << 8) | (processor_span[2] << 16) | (processor_span[3] << 24); - processor_span = processor_span.slice(4); - AML_DEBUG_PRINT("PBlkAddress"); - { - AML_DEBUG_INDENT_SCOPE(); - AML_DEBUG_PRINT("0x{8H}", p_blk_address); - } - - auto p_blk_length = processor_span[0]; - processor_span = processor_span.slice(1); - AML_DEBUG_PRINT("PBlkLength"); - { - AML_DEBUG_INDENT_SCOPE(); - AML_DEBUG_PRINT("0x{2H}", p_blk_length); - } - - AML_TRY_PARSE(term_list, AML::TermList, processor_span); - - return AML::NamedObj { - .object = AML::NamedObj::Processor { - .name = name_string.release_value(), - .processor_id = processor_id, - .p_blk_address = p_blk_address, - .p_blk_length = p_blk_length, - .term_list = term_list.release_value() - } - }; - } - case AML::Byte::ExtMutexOp: - { - span = span.slice(2); - - AML_DEBUG_PRINT("Mutex"); - AML_DEBUG_INDENT_SCOPE(); - - AML_TRY_PARSE(name_string, AML::NameString, span); - - if (span.size() == 0) - return {}; - auto sync_level = span[0]; - span = span.slice(1); - - return AML::NamedObj { - .object = AML::NamedObj::Mutex { - .name = name_string.release_value(), - .sync_level = sync_level - } - }; - } - GEN_PARSE_CASE_TODO(ExtCreateFieldOp) - GEN_PARSE_CASE_TODO(ExtPowerResOp) - GEN_PARSE_CASE_TODO(ExtThermalZoneOp) - GEN_PARSE_CASE_TODO(ExtBankFieldOp) - GEN_PARSE_CASE_TODO(ExtDataRegionOp) - GEN_PARSE_CASE_TODO(ExtEventOp) - GEN_PARSE_CASE_TODO(ExtIndexFieldOp) - default: - ASSERT_NOT_REACHED(); - } - } - - switch (static_cast(span[0])) - { -#define GEN_NAMED_OBJ_CASE_CREATE_SIZED_FIELD(NAME) \ - case AML::Byte::Create##NAME##FieldOp: \ - { \ - span = span.slice(1); \ - \ - AML_DEBUG_PRINT("Create{}Field", #NAME); \ - AML_DEBUG_INDENT_SCOPE(); \ - \ - AML_TRY_PARSE(buffer, AML::TermArg, span); \ - AML_TRY_PARSE(index, AML::TermArg, span); \ - AML_TRY_PARSE(name, AML::NameString, span); \ - \ - return AML::NamedObj { \ - .object = AML::NamedObj::CreateSizedField { \ - .type = CreateSizedField::Type::NAME, \ - .buffer = buffer.release_value(), \ - .index = index.release_value(), \ - .name = name.release_value() \ - } \ - }; \ - } - GEN_NAMED_OBJ_CASE_CREATE_SIZED_FIELD(Bit) - GEN_NAMED_OBJ_CASE_CREATE_SIZED_FIELD(Byte) - GEN_NAMED_OBJ_CASE_CREATE_SIZED_FIELD(Word) - GEN_NAMED_OBJ_CASE_CREATE_SIZED_FIELD(DWord) - GEN_NAMED_OBJ_CASE_CREATE_SIZED_FIELD(QWord) -#undef GEN_NAMED_OBJ_CASE_CREATE_SIZED_FIELD - - case AML::Byte::MethodOp: - { - span = span.slice(1); - - AML_DEBUG_PRINT("Method"); - AML_DEBUG_INDENT_SCOPE(); - - AML_TRY_PARSE_PACKAGE(method_span); - AML_TRY_PARSE(name_string, AML::NameString, method_span); - - if (method_span.size() == 0) - return {}; - auto method_flags = method_span[0]; - method_span = method_span.slice(1); - - uint8_t argument_count = method_flags & 0x07; - bool serialized = method_flags & 0x08; - uint8_t sync_level = method_flags >> 4; - - AML_DEBUG_PRINT("ArgumentCount: {}", argument_count); - AML_DEBUG_PRINT("Serialized: {}", serialized); - AML_DEBUG_PRINT("SyncLevel: {}", sync_level); - - AML_TRY_PARSE(term_list, AML::TermList, method_span); - - return AML::NamedObj { - .object = AML::NamedObj::Method { - .name = name_string.release_value(), - .argument_count = argument_count, - .serialized = serialized, - .sync_level = sync_level, - .term_list = term_list.release_value() - } - }; - } - GEN_PARSE_CASE_TODO(ExternalOp) - default: - ASSERT_NOT_REACHED(); - } - } -#pragma GCC diagnostic pop - - - // Object - - bool AML::Object::can_parse(BAN::ConstByteSpan span) - { - if (AML::NameSpaceModifierObj::can_parse(span)) - return true; - if (AML::NamedObj::can_parse(span)) - return true; - return false; - } - - BAN::Optional AML::Object::parse(BAN::ConstByteSpan& span) - { - AML_DEBUG_PRINT_FN(); - ASSERT(can_parse(span)); - AML_TRY_PARSE_IF_CAN(AML::NameSpaceModifierObj); - AML_TRY_PARSE_IF_CAN(AML::NamedObj); - ASSERT_NOT_REACHED(); - } - - - // StatementOpcode - - bool AML::StatementOpcode::can_parse(BAN::ConstByteSpan span) - { - if (span.size() < 1) - return false; - if (static_cast(span[0]) == AML::Byte::ExtOpPrefix) - { - if (span.size() < 2) - return false; - switch (static_cast(span[1])) - { - case AML::Byte::ExtFatalOp: - case AML::Byte::ExtReleaseOp: - case AML::Byte::ExtResetOp: - case AML::Byte::ExtSignalOp: - case AML::Byte::ExtSleepOp: - case AML::Byte::ExtStallOp: - return true; - default: - return false; - } - } - switch (static_cast(span[0])) - { - case AML::Byte::BreakOp: - case AML::Byte::BreakPointOp: - case AML::Byte::ContinueOp: - case AML::Byte::IfOp: - case AML::Byte::NoopOp: - case AML::Byte::NotifyOp: - case AML::Byte::ReturnOp: - case AML::Byte::WhileOp: - return true; - default: - return false; - } - } - - BAN::Optional AML::StatementOpcode::parse(BAN::ConstByteSpan& span) - { - AML_DEBUG_PRINT_FN(); - ASSERT(can_parse(span)); - - if (static_cast(span[0]) == AML::Byte::ExtOpPrefix) - { - switch (static_cast(span[1])) - { - case AML::Byte::ExtReleaseOp: - { - span = span.slice(2); - - AML_DEBUG_PRINT("Release"); - AML_DEBUG_INDENT_SCOPE(); - - AML_TRY_PARSE(mutex, AML::SuperName, span); - - return AML::StatementOpcode { - .opcode = AML::StatementOpcode::Release { - .mutex = mutex.release_value() - } - }; - } - - GEN_PARSE_CASE_TODO(ExtFatalOp) - GEN_PARSE_CASE_TODO(ExtResetOp) - GEN_PARSE_CASE_TODO(ExtSignalOp) - GEN_PARSE_CASE_TODO(ExtSleepOp) - GEN_PARSE_CASE_TODO(ExtStallOp) - default: - ASSERT_NOT_REACHED(); - } - } - - switch (static_cast(span[0])) - { - case AML::Byte::IfOp: - { - span = span.slice(1); - - AML_DEBUG_PRINT("If"); - AML_DEBUG_INDENT_SCOPE(); - - AML_TRY_PARSE_PACKAGE(if_span); - AML_TRY_PARSE(predicate, AML::TermArg, if_span); - AML_TRY_PARSE(true_list, AML::TermList, if_span); - - TermList false_list; - if (if_span.size() > 0 && static_cast(if_span[0]) == AML::Byte::ElseOp) - { - if_span = if_span.slice(1); - AML_TRY_PARSE(opt_false_list, AML::TermList, if_span); - false_list = opt_false_list.release_value(); - } - - return AML::StatementOpcode { - .opcode = AML::StatementOpcode::IfElse { - .predicate = predicate.release_value(), - .true_list = true_list.release_value(), - .false_list = BAN::move(false_list) - } - }; - } - case AML::Byte::NotifyOp: - { - span = span.slice(1); - - AML_DEBUG_PRINT("Notify"); - AML_DEBUG_INDENT_SCOPE(); - - AML_TRY_PARSE(object, AML::SuperName, span); - AML_TRY_PARSE(value, AML::TermArg, span); - - return AML::StatementOpcode { - .opcode = AML::StatementOpcode::Notify { - .object = object.release_value(), - .value = value.release_value() - } - }; - } - case AML::Byte::ReturnOp: - { - span = span.slice(1); - - AML_DEBUG_PRINT("Return"); - AML_DEBUG_INDENT_SCOPE(); - - AML::StatementOpcode::Return result; - if (AML::DataRefObject::can_parse(span)) - { - auto opt_arg = AML::DataRefObject::parse(span); - if (!opt_arg.has_value()) - return {}; - result.arg = opt_arg.release_value(); - } - return result; - } - - GEN_PARSE_CASE_TODO(BreakOp) - GEN_PARSE_CASE_TODO(BreakPointOp) - GEN_PARSE_CASE_TODO(ContinueOp) - GEN_PARSE_CASE_TODO(NoopOp) - GEN_PARSE_CASE_TODO(WhileOp) - default: - ASSERT_NOT_REACHED(); - } - - ASSERT_NOT_REACHED(); - } - - - // MethodInvocation - - bool AML::MethodInvocation::can_parse(BAN::ConstByteSpan span) - { - if (AML::NameString::can_parse(span)) - return true; - return false; - } - - BAN::Optional AML::MethodInvocation::parse(BAN::ConstByteSpan& span) - { - AML_DEBUG_PRINT_FN(); - ASSERT(can_parse(span)); - - AML_TRY_PARSE(name, AML::NameString, span); - - //AML_DEBUG_TODO("Can't parse args, since number of args is not known."); - return {}; - - BAN::Vector term_args; - while (span.size() > 0 && AML::TermArg::can_parse(span)) - { - auto term_arg = AML::TermArg::parse(span); - if (!term_arg.has_value()) - return {}; - MUST(term_args.push_back(term_arg.release_value())); - } - - return AML::MethodInvocation { - .name = name.release_value(), - .term_args = BAN::move(term_args) - }; - } - - - // ExpressionOpcode - - bool AML::ExpressionOpcode::can_parse(BAN::ConstByteSpan span) - { - if (span.size() < 1) - return false; - - if (AML::MethodInvocation::can_parse(span)) - return true; - - if (static_cast(span[0]) == AML::Byte::ExtOpPrefix) - { - if (span.size() < 2) - return false; - switch (static_cast(span[1])) - { - case AML::Byte::ExtCondRefOfOp: - case AML::Byte::ExtLoadTableOp: - case AML::Byte::ExtLoadOp: - case AML::Byte::ExtAcquireOp: - case AML::Byte::ExtWaitOp: - case AML::Byte::ExtFromBCDOp: - case AML::Byte::ExtToBCDOp: - case AML::Byte::ExtTimerOp: - return true; - default: - return false; - } - } - - switch (static_cast(span[0])) - { - case AML::Byte::PackageOp: - case AML::Byte::VarPackageOp: - case AML::Byte::BufferOp: - case AML::Byte::StoreOp: - case AML::Byte::RefOfOp: - case AML::Byte::AddOp: - case AML::Byte::ConcatOp: - case AML::Byte::SubtractOp: - case AML::Byte::IncrementOp: - case AML::Byte::DecrementOp: - 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::NotOp: - case AML::Byte::FindSetLeftBitOp: - case AML::Byte::FindSetRightBitOp: - case AML::Byte::DerefOfOp: - case AML::Byte::ConcatResOp: - case AML::Byte::ModOp: - case AML::Byte::SizeOfOp: - case AML::Byte::IndexOp: - case AML::Byte::MatchOp: - case AML::Byte::ObjectTypeOp: - case AML::Byte::LAndOp: - case AML::Byte::LOrOp: - case AML::Byte::LNotOp: - case AML::Byte::LEqualOp: - case AML::Byte::LGreaterOp: - case AML::Byte::LLessOp: - case AML::Byte::ToBufferOp: - case AML::Byte::ToDecimalStringOp: - case AML::Byte::ToHexStringOp: - case AML::Byte::ToIntegerOp: - case AML::Byte::ToStringOp: - case AML::Byte::CopyObjectOp: - case AML::Byte::MidOp: - return true; - default: - return false; - } - } - -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wstack-usage=" - BAN::Optional AML::ExpressionOpcode::parse(BAN::ConstByteSpan& span) - { - AML_DEBUG_PRINT_FN(); - ASSERT(can_parse(span)); - - AML_TRY_PARSE_IF_CAN(AML::Buffer); - AML_TRY_PARSE_IF_CAN(AML::Package); - AML_TRY_PARSE_IF_CAN(AML::VarPackage); - AML_TRY_PARSE_IF_CAN(AML::MethodInvocation); - - if (static_cast(span[0]) == AML::Byte::ExtOpPrefix) - { - switch (static_cast(span[1])) - { - case AML::Byte::ExtAcquireOp: - { - span = span.slice(2); - - AML_DEBUG_PRINT("Acquire"); - AML_DEBUG_INDENT_SCOPE(); - - AML_TRY_PARSE(mutex, AML::SuperName, span); - - if (span.size() < 2) - return {}; - uint16_t timeout = span[0] | (span[1] << 8); - span = span.slice(2); - - return AML::ExpressionOpcode { - .opcode = AML::ExpressionOpcode::Acquire { - .mutex = mutex.release_value(), - .timeout = timeout - } - }; - } - GEN_PARSE_CASE_TODO(ExtCondRefOfOp) - GEN_PARSE_CASE_TODO(ExtLoadTableOp) - GEN_PARSE_CASE_TODO(ExtLoadOp) - GEN_PARSE_CASE_TODO(ExtWaitOp) - GEN_PARSE_CASE_TODO(ExtFromBCDOp) - GEN_PARSE_CASE_TODO(ExtToBCDOp) - GEN_PARSE_CASE_TODO(ExtTimerOp) - default: - ASSERT_NOT_REACHED(); - } - } - - switch (static_cast(span[0])) - { -#define GEN_EXPRESSION_OPCODE_CASE_UNARY_OP(NAME) \ - case AML::Byte::NAME##Op: \ - { \ - span = span.slice(1); \ - \ - AML_DEBUG_PRINT(#NAME); \ - AML_DEBUG_INDENT_SCOPE(); \ - \ - AML_TRY_PARSE(object, AML::SuperName, span); \ - \ - return AML::ExpressionOpcode { \ - .opcode = AML::ExpressionOpcode::UnaryOp { \ - .type = UnaryOp::Type::NAME, \ - .object = object.release_value() \ - } \ - }; \ - } - GEN_EXPRESSION_OPCODE_CASE_UNARY_OP(Decrement) - GEN_EXPRESSION_OPCODE_CASE_UNARY_OP(Increment) - GEN_EXPRESSION_OPCODE_CASE_UNARY_OP(RefOf) - GEN_EXPRESSION_OPCODE_CASE_UNARY_OP(SizeOf) -#undef GEN_EXPRESSION_OPCODE_CASE_UNARY_OP - -#define GEN_EXPRESSION_OPCODE_CASE_BINARY_OP(NAME) \ - case AML::Byte::NAME##Op: \ - { \ - span = span.slice(1); \ - \ - AML_DEBUG_PRINT(#NAME); \ - AML_DEBUG_INDENT_SCOPE(); \ - \ - AML_TRY_PARSE(source1, AML::TermArg, span); \ - AML_TRY_PARSE(source2, AML::TermArg, span); \ - AML_TRY_PARSE(target, AML::SuperName, span); \ - \ - return AML::ExpressionOpcode { \ - .opcode = AML::ExpressionOpcode::BinaryOp { \ - .type = BinaryOp::Type::NAME, \ - .source1 = MUST(BAN::UniqPtr::create( \ - source1.release_value()) \ - ), \ - .source2 = MUST(BAN::UniqPtr::create( \ - source2.release_value()) \ - ), \ - .target = target.release_value() \ - } \ - }; \ - } - GEN_EXPRESSION_OPCODE_CASE_BINARY_OP(Add) - GEN_EXPRESSION_OPCODE_CASE_BINARY_OP(And) - GEN_EXPRESSION_OPCODE_CASE_BINARY_OP(Multiply) - GEN_EXPRESSION_OPCODE_CASE_BINARY_OP(NAnd) - GEN_EXPRESSION_OPCODE_CASE_BINARY_OP(NOr) - GEN_EXPRESSION_OPCODE_CASE_BINARY_OP(Or) - GEN_EXPRESSION_OPCODE_CASE_BINARY_OP(Subtract) - GEN_EXPRESSION_OPCODE_CASE_BINARY_OP(XOr) - GEN_EXPRESSION_OPCODE_CASE_BINARY_OP(ShiftLeft) - GEN_EXPRESSION_OPCODE_CASE_BINARY_OP(ShiftRight) -#undef GEN_EXPRESSION_OPCODE_CASE_BINARY_OP - -#define GEN_EXPRESSION_OPCODE_CASE_LOGICAL_BINARY_OP(NAME) \ - case AML::Byte::L##NAME##Op: \ - { \ - span = span.slice(1); \ - \ - AML_DEBUG_PRINT("L{}", #NAME); \ - AML_DEBUG_INDENT_SCOPE(); \ - \ - AML_TRY_PARSE(operand1, AML::TermArg, span); \ - AML_TRY_PARSE(operand2, AML::TermArg, span); \ - \ - return AML::ExpressionOpcode { \ - .opcode = AML::ExpressionOpcode::LogicalBinaryOp { \ - .type = LogicalBinaryOp::Type::NAME, \ - .operand1 = MUST(BAN::UniqPtr::create( \ - operand1.release_value()) \ - ), \ - .operand2 = MUST(BAN::UniqPtr::create( \ - operand2.release_value()) \ - ) \ - } \ - }; \ - } - GEN_EXPRESSION_OPCODE_CASE_LOGICAL_BINARY_OP(And) - GEN_EXPRESSION_OPCODE_CASE_LOGICAL_BINARY_OP(Or) - GEN_EXPRESSION_OPCODE_CASE_LOGICAL_BINARY_OP(Equal) - GEN_EXPRESSION_OPCODE_CASE_LOGICAL_BINARY_OP(Greater) - GEN_EXPRESSION_OPCODE_CASE_LOGICAL_BINARY_OP(Less) -#undef GEN_EXPRESSION_OPCODE_CASE_LOGICAL_BINARY_OP - -#define GEN_EXPRESSION_OPCODE_CASE_TARGET_OPERAND(NAME) \ - case AML::Byte::NAME##Op: \ - { \ - span = span.slice(1); \ - \ - AML_DEBUG_PRINT(#NAME); \ - AML_DEBUG_INDENT_SCOPE(); \ - \ - AML_TRY_PARSE(operand, AML::TermArg, span); \ - AML_TRY_PARSE(target, AML::SuperName, span); \ - \ - return AML::ExpressionOpcode { \ - .opcode = AML::ExpressionOpcode::NAME { \ - .operand = MUST(BAN::UniqPtr::create( \ - operand.release_value()) \ - ), \ - .target = target.release_value() \ - } \ - }; \ - } - GEN_EXPRESSION_OPCODE_CASE_TARGET_OPERAND(ToBuffer) - GEN_EXPRESSION_OPCODE_CASE_TARGET_OPERAND(ToDecimalString) - GEN_EXPRESSION_OPCODE_CASE_TARGET_OPERAND(ToHexString) - GEN_EXPRESSION_OPCODE_CASE_TARGET_OPERAND(ToInteger) -#undef GEN_EXPRESSION_OPCODE_CASE_TARGET_OPERAND - - case AML::Byte::StoreOp: - { - span = span.slice(1); - - AML_DEBUG_PRINT("Store"); - AML_DEBUG_INDENT_SCOPE(); - - AML_TRY_PARSE(source, AML::TermArg, span); - AML_TRY_PARSE(target, AML::SuperName, span); - - return AML::ExpressionOpcode { - .opcode = AML::ExpressionOpcode::Store { - .source = MUST(BAN::UniqPtr::create( - source.release_value()) - ), - .target = target.release_value() - } - }; - } - GEN_PARSE_CASE_TODO(BufferOp) - GEN_PARSE_CASE_TODO(ConcatOp) - GEN_PARSE_CASE_TODO(DivideOp) - GEN_PARSE_CASE_TODO(NotOp) - GEN_PARSE_CASE_TODO(FindSetLeftBitOp) - GEN_PARSE_CASE_TODO(FindSetRightBitOp) - GEN_PARSE_CASE_TODO(DerefOfOp) - GEN_PARSE_CASE_TODO(ConcatResOp) - GEN_PARSE_CASE_TODO(ModOp) - GEN_PARSE_CASE_TODO(IndexOp) - GEN_PARSE_CASE_TODO(MatchOp) - GEN_PARSE_CASE_TODO(ObjectTypeOp) - GEN_PARSE_CASE_TODO(LNotOp) - GEN_PARSE_CASE_TODO(ToStringOp) - GEN_PARSE_CASE_TODO(CopyObjectOp) - GEN_PARSE_CASE_TODO(MidOp) - default: - ASSERT_NOT_REACHED(); - } - } -#pragma GCC diagnostic pop - - - // TermObj - - bool AML::TermObj::can_parse(BAN::ConstByteSpan span) - { - if (AML::Object::can_parse(span)) - return true; - if (AML::StatementOpcode::can_parse(span)) - return true; - if (AML::ExpressionOpcode::can_parse(span)) - return true; - return false; - } - -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wstack-usage=" - BAN::Optional AML::TermObj::parse(BAN::ConstByteSpan& span) - { - AML_DEBUG_PRINT_FN(); - ASSERT(can_parse(span)); - AML_TRY_PARSE_IF_CAN(AML::Object); - AML_TRY_PARSE_IF_CAN(AML::StatementOpcode); - AML_TRY_PARSE_IF_CAN(AML::ExpressionOpcode); - ASSERT_NOT_REACHED(); - } -#pragma GCC diagnostic pop - - - // TermList - - bool AML::TermList::can_parse(BAN::ConstByteSpan span) - { - if (span.size() == 0) - return true; - return TermObj::can_parse(span); - } - - -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wstack-usage=" - BAN::Optional AML::TermList::parse(BAN::ConstByteSpan& span) - { - AML_DEBUG_PRINT_FN(); - ASSERT(can_parse(span)); - - TermList term_list; - while (span.size() > 0) - { - if (!TermObj::can_parse(span)) - { - AML_DEBUG_CANNOT_PARSE("AML::TermObj", span); - return term_list; - } - - auto object = TermObj::parse(span); - if (!object.has_value()) - return term_list; - - MUST(term_list.terms.push_back(object.release_value())); - } - - return term_list; - } -#pragma GCC diagnostic pop - - - // TermArg - - bool AML::TermArg::can_parse(BAN::ConstByteSpan span) - { - if (AML::ExpressionOpcode::can_parse(span)) - return true; - if (AML::DataObject::can_parse(span)) - return true; - if (AML::ArgObj::can_parse(span)) - return true; - if (AML::LocalObj::can_parse(span)) - return true; - return false; - } - - BAN::Optional AML::TermArg::parse(BAN::ConstByteSpan& span) - { - AML_DEBUG_PRINT_FN(); - ASSERT(can_parse(span)); - AML_TRY_PARSE_IF_CAN(AML::ExpressionOpcode); - AML_TRY_PARSE_IF_CAN(AML::DataObject); - AML_TRY_PARSE_IF_CAN(AML::ArgObj); - AML_TRY_PARSE_IF_CAN(AML::LocalObj); - ASSERT_NOT_REACHED(); - } - - - // ReferenceTypeOpcode - - bool AML::ReferenceTypeOpcode::can_parse(BAN::ConstByteSpan span) - { - if (MethodInvocation::can_parse(span)) - return true; - if (span.size() < 1) - return false; - switch (static_cast(span[0])) - { - case AML::Byte::RefOfOp: - case AML::Byte::DerefOfOp: - case AML::Byte::IndexOp: - return true; - default: - return false; - } - } - - -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wstack-usage=" - BAN::Optional AML::ReferenceTypeOpcode::parse(BAN::ConstByteSpan& span) - { - AML_DEBUG_PRINT_FN(); - ASSERT(can_parse(span)); - - if (MethodInvocation::can_parse(span)) - { - auto method = MethodInvocation::parse(span); - if (!method.has_value()) - return {}; - return AML::ReferenceTypeOpcode { - .opcode = AML::ReferenceTypeOpcode::UserTermObj { - .method = method.release_value() - } - }; - } - - switch (static_cast(span[0])) - { - case AML::Byte::RefOfOp: - { - span = span.slice(1); - - AML_DEBUG_PRINT("RefOf"); - AML_DEBUG_INDENT_SCOPE(); - - AML_TRY_PARSE(target, AML::SuperName, span); - - return AML::ReferenceTypeOpcode { - .opcode = AML::ReferenceTypeOpcode::RefOf { - .target = target.release_value() - } - }; - } - case AML::Byte::DerefOfOp: - { - span = span.slice(1); - - AML_DEBUG_PRINT("DerefOf"); - AML_DEBUG_INDENT_SCOPE(); - - AML_TRY_PARSE(source, AML::TermArg, span); - - return AML::ReferenceTypeOpcode { - .opcode = AML::ReferenceTypeOpcode::DerefOf { - .source = source.release_value() - } - }; - } - case AML::Byte::IndexOp: - { - span = span.slice(1); - - AML_DEBUG_PRINT("Index"); - AML_DEBUG_INDENT_SCOPE(); - - AML_TRY_PARSE(source, AML::TermArg, span); - AML_TRY_PARSE(index, AML::TermArg, span); - AML_TRY_PARSE(destination, AML::SuperName, span); - - return AML::ReferenceTypeOpcode { - .opcode = AML::ReferenceTypeOpcode::Index { - .source = source.release_value(), - .index = index.release_value(), - .destination = destination.release_value() - } - }; - } - default: - ASSERT_NOT_REACHED(); - } - } -#pragma GCC diagnostic pop - -}