diff --git a/kernel/CMakeLists.txt b/kernel/CMakeLists.txt index 3f2ffa44b0..4b8b2a15af 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 0309dc2f49..70f209e889 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 ebbc5a0e85..80221c6261 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 0000000000..6e3e1f0704 --- /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 0000000000..204a8e1a72 --- /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 0000000000..943830a592 --- /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 0000000000..2e974b709f --- /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 0000000000..0cbd4e3154 --- /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 0000000000..7184175b2b --- /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 0000000000..89dff860d5 --- /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 f232bdccc6..97b4ee3847 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 c7f812112d..721f41010a 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 0000000000..a9c58a9a51 --- /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 0000000000..a1e9d7b497 --- /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 0000000000..7722cea94e --- /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 0000000000..f4ff270abe --- /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 0000000000..629d3e4b12 --- /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 + +}