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.
This commit is contained in:
parent
e0011d22f2
commit
e7ef7a9e55
|
@ -11,6 +11,11 @@ endif()
|
||||||
set(KERNEL_SOURCES
|
set(KERNEL_SOURCES
|
||||||
font/prefs.psf.o
|
font/prefs.psf.o
|
||||||
kernel/ACPI/ACPI.cpp
|
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/APIC.cpp
|
||||||
kernel/BootInfo.cpp
|
kernel/BootInfo.cpp
|
||||||
kernel/CPUID.cpp
|
kernel/CPUID.cpp
|
||||||
|
|
|
@ -54,7 +54,7 @@ bananboot_end:
|
||||||
|
|
||||||
.section .bss, "aw", @nobits
|
.section .bss, "aw", @nobits
|
||||||
boot_stack_bottom:
|
boot_stack_bottom:
|
||||||
.skip 4096 * 4
|
.skip 4096 * 64
|
||||||
boot_stack_top:
|
boot_stack_top:
|
||||||
|
|
||||||
.global g_kernel_cmdline
|
.global g_kernel_cmdline
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <BAN/Vector.h>
|
#include <BAN/Vector.h>
|
||||||
#include <kernel/ACPI/AML.h>
|
|
||||||
#include <kernel/ACPI/Headers.h>
|
#include <kernel/ACPI/Headers.h>
|
||||||
#include <kernel/Memory/Types.h>
|
#include <kernel/Memory/Types.h>
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <kernel/ACPI/Headers.h>
|
||||||
|
|
||||||
|
namespace Kernel::ACPI
|
||||||
|
{
|
||||||
|
|
||||||
|
class AMLParser
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
~AMLParser();
|
||||||
|
|
||||||
|
static AMLParser parse_table(const SDTHeader& header);
|
||||||
|
|
||||||
|
private:
|
||||||
|
AMLParser();
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,265 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <BAN/Formatter.h>
|
||||||
|
#include <BAN/Vector.h>
|
||||||
|
#include <BAN/StringView.h>
|
||||||
|
#include <kernel/Debug.h>
|
||||||
|
|
||||||
|
#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,
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,101 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <BAN/ByteSpan.h>
|
||||||
|
#include <BAN/Optional.h>
|
||||||
|
#include <BAN/String.h>
|
||||||
|
#include <BAN/UniqPtr.h>
|
||||||
|
#include <BAN/Variant.h>
|
||||||
|
#include <BAN/Vector.h>
|
||||||
|
#include <kernel/ACPI/AML/NameObject.h>
|
||||||
|
|
||||||
|
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<Integer> parse(BAN::ConstByteSpan& span);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Buffer := BufferOp PkgLength BufferSize ByteList
|
||||||
|
struct Buffer
|
||||||
|
{
|
||||||
|
Integer buffer_size;
|
||||||
|
BAN::Vector<uint8_t> data;
|
||||||
|
|
||||||
|
static bool can_parse(BAN::ConstByteSpan span);
|
||||||
|
static BAN::Optional<Buffer> 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<Integer, String, ConstObj, RevisionOp, Buffer> data;
|
||||||
|
|
||||||
|
static bool can_parse(BAN::ConstByteSpan span);
|
||||||
|
static BAN::Optional<ComputationalData> parse(BAN::ConstByteSpan& span);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct DataRefObject;
|
||||||
|
|
||||||
|
// PackageElement := DataRefObject | NameString
|
||||||
|
using PackageElement = BAN::Variant<BAN::UniqPtr<DataRefObject>, NameString>;
|
||||||
|
|
||||||
|
// DefPackage := PackageOp PkgLength NumElements PackageElementList
|
||||||
|
struct Package
|
||||||
|
{
|
||||||
|
BAN::Vector<PackageElement> elements;
|
||||||
|
|
||||||
|
static bool can_parse(BAN::ConstByteSpan span);
|
||||||
|
static BAN::Optional<Package> parse(BAN::ConstByteSpan& span);
|
||||||
|
};
|
||||||
|
|
||||||
|
// DefVarPackage := VarPackageOp PkgLength VarNumElements PackageElementList
|
||||||
|
struct VarPackage
|
||||||
|
{
|
||||||
|
BAN::Vector<PackageElement> elements;
|
||||||
|
|
||||||
|
static bool can_parse(BAN::ConstByteSpan span);
|
||||||
|
static BAN::Optional<VarPackage> parse(BAN::ConstByteSpan& span);
|
||||||
|
};
|
||||||
|
|
||||||
|
// DataObject := ComputationalData | DefPackage | DefVarPackage
|
||||||
|
struct DataObject
|
||||||
|
{
|
||||||
|
BAN::Variant<ComputationalData, Package, VarPackage> data;
|
||||||
|
|
||||||
|
static bool can_parse(BAN::ConstByteSpan span);
|
||||||
|
static BAN::Optional<DataObject> parse(BAN::ConstByteSpan& span);
|
||||||
|
};
|
||||||
|
|
||||||
|
// DataRefObject := DataObject | ObjectReference
|
||||||
|
struct DataRefObject
|
||||||
|
{
|
||||||
|
BAN::Variant<DataObject, Integer> object;
|
||||||
|
|
||||||
|
static bool can_parse(BAN::ConstByteSpan span);
|
||||||
|
static BAN::Optional<DataRefObject> parse(BAN::ConstByteSpan& span);
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,56 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <BAN/ByteSpan.h>
|
||||||
|
#include <BAN/Optional.h>
|
||||||
|
|
||||||
|
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<ArgObj> 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<LocalObj> parse(BAN::ConstByteSpan& span);
|
||||||
|
};
|
||||||
|
|
||||||
|
// DebugObj := DebugOp
|
||||||
|
struct DebugObj
|
||||||
|
{
|
||||||
|
static bool can_parse(BAN::ConstByteSpan span);
|
||||||
|
static BAN::Optional<DebugObj> parse(BAN::ConstByteSpan& span);
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,46 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <BAN/ByteSpan.h>
|
||||||
|
#include <BAN/Optional.h>
|
||||||
|
#include <BAN/String.h>
|
||||||
|
#include <BAN/UniqPtr.h>
|
||||||
|
#include <BAN/Variant.h>
|
||||||
|
#include <BAN/Vector.h>
|
||||||
|
#include <kernel/ACPI/AML/MiscObject.h>
|
||||||
|
|
||||||
|
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<BAN::String> path;
|
||||||
|
|
||||||
|
static bool can_parse(BAN::ConstByteSpan span);
|
||||||
|
static BAN::Optional<NameString> parse(BAN::ConstByteSpan& span);
|
||||||
|
};
|
||||||
|
|
||||||
|
// SimpleName := NameString | ArgObj | LocalObj
|
||||||
|
struct SimpleName
|
||||||
|
{
|
||||||
|
BAN::Variant<NameString, ArgObj, LocalObj> name;
|
||||||
|
|
||||||
|
static bool can_parse(BAN::ConstByteSpan span);
|
||||||
|
static BAN::Optional<SimpleName> parse(BAN::ConstByteSpan& span);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ReferenceTypeOpcode;
|
||||||
|
|
||||||
|
// SuperName := SimpleName | DebugObj | ReferenceTypeOpcode
|
||||||
|
struct SuperName
|
||||||
|
{
|
||||||
|
BAN::Variant<SimpleName, DebugObj, BAN::UniqPtr<ReferenceTypeOpcode>> name;
|
||||||
|
|
||||||
|
static bool can_parse(BAN::ConstByteSpan span);
|
||||||
|
static BAN::Optional<SuperName> parse(BAN::ConstByteSpan& span);
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <BAN/ByteSpan.h>
|
||||||
|
#include <BAN/Optional.h>
|
||||||
|
#include <kernel/ACPI/AML/Bytes.h>
|
||||||
|
|
||||||
|
namespace Kernel::ACPI::AML
|
||||||
|
{
|
||||||
|
|
||||||
|
struct PkgLength
|
||||||
|
{
|
||||||
|
static BAN::Optional<BAN::ConstByteSpan> 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<uint32_t>(span[i]) << (i * 8 - 4);
|
||||||
|
|
||||||
|
if (span.size() < length)
|
||||||
|
return {};
|
||||||
|
|
||||||
|
auto result = span.slice(count, length - count);
|
||||||
|
span = span.slice(length);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,328 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <BAN/ByteSpan.h>
|
||||||
|
#include <BAN/Optional.h>
|
||||||
|
#include <BAN/UniqPtr.h>
|
||||||
|
#include <BAN/Variant.h>
|
||||||
|
#include <BAN/Vector.h>
|
||||||
|
#include <kernel/ACPI/AML/DataObject.h>
|
||||||
|
#include <kernel/ACPI/AML/MiscObject.h>
|
||||||
|
#include <kernel/ACPI/AML/NameObject.h>
|
||||||
|
|
||||||
|
namespace Kernel::ACPI::AML
|
||||||
|
{
|
||||||
|
// ACPI Spec 6.4, Section 20.2.5
|
||||||
|
|
||||||
|
struct TermObj;
|
||||||
|
struct TermArg;
|
||||||
|
|
||||||
|
// TermList := Nothing | TermObj TermList
|
||||||
|
struct TermList
|
||||||
|
{
|
||||||
|
BAN::Vector<TermObj> terms;
|
||||||
|
|
||||||
|
static bool can_parse(BAN::ConstByteSpan);
|
||||||
|
static BAN::Optional<TermList> parse(BAN::ConstByteSpan&);
|
||||||
|
};
|
||||||
|
|
||||||
|
// MethodInvocation := NameString TermArgList
|
||||||
|
struct MethodInvocation
|
||||||
|
{
|
||||||
|
NameString name;
|
||||||
|
BAN::Vector<TermArg> term_args;
|
||||||
|
|
||||||
|
static bool can_parse(BAN::ConstByteSpan);
|
||||||
|
static BAN::Optional<MethodInvocation> 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<TermArg> source1;
|
||||||
|
BAN::UniqPtr<TermArg> source2;
|
||||||
|
SuperName target;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct LogicalBinaryOp
|
||||||
|
{
|
||||||
|
enum class Type
|
||||||
|
{
|
||||||
|
And,
|
||||||
|
Equal,
|
||||||
|
Greater,
|
||||||
|
Less,
|
||||||
|
Or,
|
||||||
|
// GreaterEqual, LessEqual, NotEqual handled by Not + LogicalBinaryOp
|
||||||
|
};
|
||||||
|
Type type;
|
||||||
|
BAN::UniqPtr<TermArg> operand1;
|
||||||
|
BAN::UniqPtr<TermArg> operand2;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define GEN_OPCODE_STRUCT_OPERAND_TARGET(NAME) struct NAME { BAN::UniqPtr<TermArg> 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<TermArg> 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<ExpressionOpcode> parse(BAN::ConstByteSpan&);
|
||||||
|
};
|
||||||
|
|
||||||
|
// TermArg := ExpressionOpcode | DataObject | ArgObj | LocalObj
|
||||||
|
struct TermArg
|
||||||
|
{
|
||||||
|
BAN::Variant<ExpressionOpcode, DataObject, ArgObj, LocalObj> arg;
|
||||||
|
|
||||||
|
static bool can_parse(BAN::ConstByteSpan);
|
||||||
|
static BAN::Optional<TermArg> 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<Alias, Name, Scope> modifier;
|
||||||
|
|
||||||
|
static bool can_parse(BAN::ConstByteSpan);
|
||||||
|
static BAN::Optional<NameSpaceModifierObj> 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<BankField, CreateSizedField, CreateField, DataRegion,
|
||||||
|
External, OpRegion, PowerRes, Processor, ThermalZone, Device,
|
||||||
|
Event, Field, IndexField, Method, Mutex
|
||||||
|
> object;
|
||||||
|
|
||||||
|
static bool can_parse(BAN::ConstByteSpan);
|
||||||
|
static BAN::Optional<NamedObj> parse(BAN::ConstByteSpan&);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Object := NameSpaceModifierObj | NamedObj
|
||||||
|
struct Object
|
||||||
|
{
|
||||||
|
BAN::Variant<NameSpaceModifierObj, NamedObj> object;
|
||||||
|
|
||||||
|
static bool can_parse(BAN::ConstByteSpan);
|
||||||
|
static BAN::Optional<Object> 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<DataRefObject> arg;
|
||||||
|
};
|
||||||
|
|
||||||
|
BAN::Variant<IfElse, Notify, Release, Return> opcode;
|
||||||
|
|
||||||
|
static bool can_parse(BAN::ConstByteSpan);
|
||||||
|
static BAN::Optional<StatementOpcode> parse(BAN::ConstByteSpan&);
|
||||||
|
};
|
||||||
|
|
||||||
|
// TermObj := Object | StatementOpcode | ExpressionOpcode
|
||||||
|
struct TermObj
|
||||||
|
{
|
||||||
|
BAN::Variant<Object, StatementOpcode, ExpressionOpcode> term;
|
||||||
|
|
||||||
|
static bool can_parse(BAN::ConstByteSpan);
|
||||||
|
static BAN::Optional<TermObj> 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<RefOf, DerefOf, Index, UserTermObj> opcode;
|
||||||
|
|
||||||
|
static bool can_parse(BAN::ConstByteSpan);
|
||||||
|
static BAN::Optional<ReferenceTypeOpcode> parse(BAN::ConstByteSpan&);
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -93,7 +93,7 @@ namespace Kernel
|
||||||
void on_exit();
|
void on_exit();
|
||||||
|
|
||||||
private:
|
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;
|
static constexpr size_t m_userspace_stack_size = PAGE_SIZE * 4;
|
||||||
BAN::UniqPtr<VirtualRange> m_kernel_stack;
|
BAN::UniqPtr<VirtualRange> m_kernel_stack;
|
||||||
BAN::UniqPtr<VirtualRange> m_userspace_stack;
|
BAN::UniqPtr<VirtualRange> m_userspace_stack;
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#include <BAN/ScopeGuard.h>
|
#include <BAN/ScopeGuard.h>
|
||||||
#include <BAN/StringView.h>
|
#include <BAN/StringView.h>
|
||||||
#include <kernel/ACPI/ACPI.h>
|
#include <kernel/ACPI/ACPI.h>
|
||||||
|
#include <kernel/ACPI/AML.h>
|
||||||
#include <kernel/BootInfo.h>
|
#include <kernel/BootInfo.h>
|
||||||
#include <kernel/Memory/PageTable.h>
|
#include <kernel/Memory/PageTable.h>
|
||||||
|
|
||||||
|
@ -31,6 +32,11 @@ namespace Kernel::ACPI
|
||||||
if (s_instance == nullptr)
|
if (s_instance == nullptr)
|
||||||
return BAN::Error::from_errno(ENOMEM);
|
return BAN::Error::from_errno(ENOMEM);
|
||||||
TRY(s_instance->initialize_impl());
|
TRY(s_instance->initialize_impl());
|
||||||
|
|
||||||
|
auto dsdt = s_instance->get_header("DSDT", 0);
|
||||||
|
ASSERT(dsdt);
|
||||||
|
AMLParser::parse_table(*dsdt);
|
||||||
|
|
||||||
#if ARCH(x86_64)
|
#if ARCH(x86_64)
|
||||||
lai_create_namespace();
|
lai_create_namespace();
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
#include <BAN/ByteSpan.h>
|
||||||
|
#include <BAN/Variant.h>
|
||||||
|
#include <kernel/ACPI/ACPI.h>
|
||||||
|
#include <kernel/ACPI/AML.h>
|
||||||
|
|
||||||
|
#include <kernel/ACPI/AML/TermObject.h>
|
||||||
|
|
||||||
|
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<const uint8_t*>(&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 {};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,281 @@
|
||||||
|
#include <kernel/ACPI/AML/Bytes.h>
|
||||||
|
#include <kernel/ACPI/AML/DataObject.h>
|
||||||
|
#include <kernel/ACPI/AML/PackageLength.h>
|
||||||
|
|
||||||
|
namespace Kernel::ACPI
|
||||||
|
{
|
||||||
|
|
||||||
|
// Integer
|
||||||
|
|
||||||
|
bool AML::Integer::can_parse(BAN::ConstByteSpan span)
|
||||||
|
{
|
||||||
|
if (span.size() < 1)
|
||||||
|
return false;
|
||||||
|
switch (static_cast<AML::Byte>(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> AML::Integer::parse(BAN::ConstByteSpan& span)
|
||||||
|
{
|
||||||
|
AML_DEBUG_PRINT_FN();
|
||||||
|
ASSERT(can_parse(span));
|
||||||
|
|
||||||
|
switch (static_cast<AML::Byte>(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<uint64_t>(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<AML::Byte>(span[0]) == AML::Byte::BufferOp)
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
BAN::Optional<AML::Buffer> 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<uint8_t> 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<AML::Byte>(span[0]) == AML::Byte::ExtOpPrefix)
|
||||||
|
{
|
||||||
|
if (span.size() < 2)
|
||||||
|
return false;
|
||||||
|
switch (static_cast<AML::Byte>(span[1]))
|
||||||
|
{
|
||||||
|
case AML::Byte::ExtRevisionOp:
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
switch (static_cast<AML::Byte>(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> 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<AML::Byte>(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<AML::Byte>(span[0]) == AML::Byte::NAME##Op) \
|
||||||
|
return true; \
|
||||||
|
return false; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
BAN::Optional<AML::NAME> 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<PackageElement> 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<DataRefObject>::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> 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> 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();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,99 @@
|
||||||
|
#include <kernel/ACPI/AML/Bytes.h>
|
||||||
|
#include <kernel/ACPI/AML/MiscObject.h>
|
||||||
|
|
||||||
|
namespace Kernel::ACPI
|
||||||
|
{
|
||||||
|
|
||||||
|
// ArgObj
|
||||||
|
|
||||||
|
bool AML::ArgObj::can_parse(BAN::ConstByteSpan span)
|
||||||
|
{
|
||||||
|
if (span.size() < 1)
|
||||||
|
return false;
|
||||||
|
switch (static_cast<AML::Byte>(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> AML::ArgObj::parse(BAN::ConstByteSpan& span)
|
||||||
|
{
|
||||||
|
AML_DEBUG_PRINT_FN();
|
||||||
|
ASSERT(can_parse(span));
|
||||||
|
|
||||||
|
uint8_t type = static_cast<uint8_t>(span[0]) - static_cast<uint8_t>(AML::Byte::Arg0Op);
|
||||||
|
span = span.slice(1);
|
||||||
|
|
||||||
|
AML_DEBUG_PRINT("Arg{}", type);
|
||||||
|
|
||||||
|
return ArgObj { .type = static_cast<Type>(type) };
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// LocalObj
|
||||||
|
|
||||||
|
bool AML::LocalObj::can_parse(BAN::ConstByteSpan span)
|
||||||
|
{
|
||||||
|
if (span.size() < 1)
|
||||||
|
return false;
|
||||||
|
switch (static_cast<AML::Byte>(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> AML::LocalObj::parse(BAN::ConstByteSpan& span)
|
||||||
|
{
|
||||||
|
AML_DEBUG_PRINT_FN();
|
||||||
|
ASSERT(can_parse(span));
|
||||||
|
|
||||||
|
uint8_t type = static_cast<uint8_t>(span[0]) - static_cast<uint8_t>(AML::Byte::Local0Op);
|
||||||
|
span = span.slice(1);
|
||||||
|
|
||||||
|
AML_DEBUG_PRINT("Local{}", type);
|
||||||
|
|
||||||
|
return LocalObj { .type = static_cast<Type>(type) };
|
||||||
|
}
|
||||||
|
|
||||||
|
// DebugObj
|
||||||
|
|
||||||
|
bool AML::DebugObj::can_parse(BAN::ConstByteSpan span)
|
||||||
|
{
|
||||||
|
if (span.size() < 2)
|
||||||
|
return false;
|
||||||
|
if (static_cast<AML::Byte>(span[0]) != AML::Byte::ExtOpPrefix)
|
||||||
|
return false;
|
||||||
|
if (static_cast<AML::Byte>(span[1]) != AML::Byte::ExtDebugOp)
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
BAN::Optional<AML::DebugObj> AML::DebugObj::parse(BAN::ConstByteSpan& span)
|
||||||
|
{
|
||||||
|
AML_DEBUG_PRINT_FN();
|
||||||
|
ASSERT(can_parse(span));
|
||||||
|
|
||||||
|
span = span.slice(2);
|
||||||
|
return DebugObj {};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,162 @@
|
||||||
|
#include <kernel/ACPI/AML/Bytes.h>
|
||||||
|
#include <kernel/ACPI/AML/NameObject.h>
|
||||||
|
#include <kernel/ACPI/AML/TermObject.h>
|
||||||
|
|
||||||
|
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<AML::Byte>(span[0]) == AML::Byte::DualNamePrefix)
|
||||||
|
return true;
|
||||||
|
if (static_cast<AML::Byte>(span[0]) == AML::Byte::MultiNamePrefix)
|
||||||
|
return true;
|
||||||
|
if (is_lead_name_char(span[0]))
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
BAN::Optional<AML::NameString> 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<uint8_t>(AML::Byte::DualNamePrefix):
|
||||||
|
name_count = 2;
|
||||||
|
span = span.slice(1);
|
||||||
|
break;
|
||||||
|
case static_cast<uint8_t>(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<const char*>(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> 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> 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<ReferenceTypeOpcode>::create(opcode.release_value())) };
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue