From e7ef7a9e559f4bee5baf88d6e913d8290a113684 Mon Sep 17 00:00:00 2001 From: Bananymous Date: Sun, 7 Apr 2024 02:54:02 +0300 Subject: [PATCH] Kernel: Implement barebones AML parser This implements only parsing for AML in qemu. InvokeMethods are not parsed since number of arguments to Methods is not yet known. Parsing AML uses multiple kilobytes of stack space, so I increased boot stack size by a lot :D I am not sure where my own AML is going, but this is good start if I decide to implement full ACPI on my own. This code is very much just ugly macro expansion. Qemu has 2 DefPackage elements that I am not able to parse. Package data ends while there should be still multiple elements. --- kernel/CMakeLists.txt | 5 + kernel/arch/x86_64/boot.S | 2 +- kernel/include/kernel/ACPI/ACPI.h | 1 - kernel/include/kernel/ACPI/AML.h | 19 + kernel/include/kernel/ACPI/AML/Bytes.h | 265 +++++ kernel/include/kernel/ACPI/AML/DataObject.h | 101 ++ kernel/include/kernel/ACPI/AML/MiscObject.h | 56 + kernel/include/kernel/ACPI/AML/NameObject.h | 46 + .../include/kernel/ACPI/AML/PackageLength.h | 36 + kernel/include/kernel/ACPI/AML/TermObject.h | 328 ++++++ kernel/include/kernel/Thread.h | 2 +- kernel/kernel/ACPI/ACPI.cpp | 6 + kernel/kernel/ACPI/AML.cpp | 35 + kernel/kernel/ACPI/AML/DataObject.cpp | 281 +++++ kernel/kernel/ACPI/AML/MiscObject.cpp | 99 ++ kernel/kernel/ACPI/AML/NameObject.cpp | 162 +++ kernel/kernel/ACPI/AML/TermObject.cpp | 1031 +++++++++++++++++ 17 files changed, 2472 insertions(+), 3 deletions(-) create mode 100644 kernel/include/kernel/ACPI/AML.h create mode 100644 kernel/include/kernel/ACPI/AML/Bytes.h create mode 100644 kernel/include/kernel/ACPI/AML/DataObject.h create mode 100644 kernel/include/kernel/ACPI/AML/MiscObject.h create mode 100644 kernel/include/kernel/ACPI/AML/NameObject.h create mode 100644 kernel/include/kernel/ACPI/AML/PackageLength.h create mode 100644 kernel/include/kernel/ACPI/AML/TermObject.h create mode 100644 kernel/kernel/ACPI/AML.cpp create mode 100644 kernel/kernel/ACPI/AML/DataObject.cpp create mode 100644 kernel/kernel/ACPI/AML/MiscObject.cpp create mode 100644 kernel/kernel/ACPI/AML/NameObject.cpp create mode 100644 kernel/kernel/ACPI/AML/TermObject.cpp diff --git a/kernel/CMakeLists.txt b/kernel/CMakeLists.txt index 3f2ffa44..4b8b2a15 100644 --- a/kernel/CMakeLists.txt +++ b/kernel/CMakeLists.txt @@ -11,6 +11,11 @@ endif() 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/APIC.cpp kernel/BootInfo.cpp kernel/CPUID.cpp diff --git a/kernel/arch/x86_64/boot.S b/kernel/arch/x86_64/boot.S index 0309dc2f..70f209e8 100644 --- a/kernel/arch/x86_64/boot.S +++ b/kernel/arch/x86_64/boot.S @@ -54,7 +54,7 @@ bananboot_end: .section .bss, "aw", @nobits boot_stack_bottom: - .skip 4096 * 4 + .skip 4096 * 64 boot_stack_top: .global g_kernel_cmdline diff --git a/kernel/include/kernel/ACPI/ACPI.h b/kernel/include/kernel/ACPI/ACPI.h index ebbc5a0e..80221c62 100644 --- a/kernel/include/kernel/ACPI/ACPI.h +++ b/kernel/include/kernel/ACPI/ACPI.h @@ -1,7 +1,6 @@ #pragma once #include -#include #include #include diff --git a/kernel/include/kernel/ACPI/AML.h b/kernel/include/kernel/ACPI/AML.h new file mode 100644 index 00000000..6e3e1f07 --- /dev/null +++ b/kernel/include/kernel/ACPI/AML.h @@ -0,0 +1,19 @@ +#pragma once + +#include + +namespace Kernel::ACPI +{ + + class AMLParser + { + public: + ~AMLParser(); + + static AMLParser parse_table(const SDTHeader& header); + + private: + AMLParser(); + }; + +} diff --git a/kernel/include/kernel/ACPI/AML/Bytes.h b/kernel/include/kernel/ACPI/AML/Bytes.h new file mode 100644 index 00000000..204a8e1a --- /dev/null +++ b/kernel/include/kernel/ACPI/AML/Bytes.h @@ -0,0 +1,265 @@ +#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) + +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 + { + 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, + }; + +} diff --git a/kernel/include/kernel/ACPI/AML/DataObject.h b/kernel/include/kernel/ACPI/AML/DataObject.h new file mode 100644 index 00000000..943830a5 --- /dev/null +++ b/kernel/include/kernel/ACPI/AML/DataObject.h @@ -0,0 +1,101 @@ +#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; + + // PackageElement := DataRefObject | NameString + using PackageElement = BAN::Variant, NameString>; + + // 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/MiscObject.h b/kernel/include/kernel/ACPI/AML/MiscObject.h new file mode 100644 index 00000000..2e974b70 --- /dev/null +++ b/kernel/include/kernel/ACPI/AML/MiscObject.h @@ -0,0 +1,56 @@ +#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/NameObject.h b/kernel/include/kernel/ACPI/AML/NameObject.h new file mode 100644 index 00000000..0cbd4e31 --- /dev/null +++ b/kernel/include/kernel/ACPI/AML/NameObject.h @@ -0,0 +1,46 @@ +#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/PackageLength.h b/kernel/include/kernel/ACPI/AML/PackageLength.h new file mode 100644 index 00000000..7184175b --- /dev/null +++ b/kernel/include/kernel/ACPI/AML/PackageLength.h @@ -0,0 +1,36 @@ +#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/TermObject.h b/kernel/include/kernel/ACPI/AML/TermObject.h new file mode 100644 index 00000000..89dff860 --- /dev/null +++ b/kernel/include/kernel/ACPI/AML/TermObject.h @@ -0,0 +1,328 @@ +#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/Thread.h b/kernel/include/kernel/Thread.h index f232bdcc..97b4ee38 100644 --- a/kernel/include/kernel/Thread.h +++ b/kernel/include/kernel/Thread.h @@ -93,7 +93,7 @@ namespace Kernel void on_exit(); private: - static constexpr size_t m_kernel_stack_size = PAGE_SIZE * 4; + static constexpr size_t m_kernel_stack_size = PAGE_SIZE * 64; static constexpr size_t m_userspace_stack_size = PAGE_SIZE * 4; BAN::UniqPtr m_kernel_stack; BAN::UniqPtr m_userspace_stack; diff --git a/kernel/kernel/ACPI/ACPI.cpp b/kernel/kernel/ACPI/ACPI.cpp index c7f81211..721f4101 100644 --- a/kernel/kernel/ACPI/ACPI.cpp +++ b/kernel/kernel/ACPI/ACPI.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include #include @@ -31,6 +32,11 @@ namespace Kernel::ACPI if (s_instance == nullptr) return BAN::Error::from_errno(ENOMEM); TRY(s_instance->initialize_impl()); + + auto dsdt = s_instance->get_header("DSDT", 0); + ASSERT(dsdt); + AMLParser::parse_table(*dsdt); + #if ARCH(x86_64) lai_create_namespace(); #endif diff --git a/kernel/kernel/ACPI/AML.cpp b/kernel/kernel/ACPI/AML.cpp new file mode 100644 index 00000000..a9c58a9a --- /dev/null +++ b/kernel/kernel/ACPI/AML.cpp @@ -0,0 +1,35 @@ +#include +#include +#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) + { + dprintln("Parsing {}, {} bytes of AML", header, header.length - sizeof(header)); + + 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 term_list = AML::TermList::parse(aml_raw); + if (!term_list.has_value()) + dwarnln("Failed to parse AML term_list"); + } + + return {}; + } + +} diff --git a/kernel/kernel/ACPI/AML/DataObject.cpp b/kernel/kernel/ACPI/AML/DataObject.cpp new file mode 100644 index 00000000..a1e9d7b4 --- /dev/null +++ b/kernel/kernel/ACPI/AML/DataObject.cpp @@ -0,0 +1,281 @@ +#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); + + if (buffer_span.size() < buffer_size->value) + { + AML_DEBUG_ERROR("Buffer size {} bytes and span only {} bytes", buffer_size->value, buffer_span.size()); + return {}; + } + + BAN::Vector data; + MUST(data.resize(buffer_size->value)); + for (size_t i = 0; i < buffer_size->value; 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; 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 {}; \ + } \ + } \ + \ + 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/MiscObject.cpp b/kernel/kernel/ACPI/AML/MiscObject.cpp new file mode 100644 index 00000000..7722cea9 --- /dev/null +++ b/kernel/kernel/ACPI/AML/MiscObject.cpp @@ -0,0 +1,99 @@ +#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 new file mode 100644 index 00000000..f4ff270a --- /dev/null +++ b/kernel/kernel/ACPI/AML/NameObject.cpp @@ -0,0 +1,162 @@ +#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/TermObject.cpp b/kernel/kernel/ACPI/AML/TermObject.cpp new file mode 100644 index 00000000..629d3e4b --- /dev/null +++ b/kernel/kernel/ACPI/AML/TermObject.cpp @@ -0,0 +1,1031 @@ +#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 + +}