Kernel: Rewrite whole AML parser
Now AML parsing is actually done while respecting namespaces and scopes. I implemented the minimal functionality to parse qemu's AML. Next step is to implement AML interpreting and then we can drop lai as a dependency.
This commit is contained in:
parent
090a294017
commit
b16e65168f
|
@ -12,10 +12,11 @@ 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.cpp
|
||||||
kernel/ACPI/AML/DataObject.cpp
|
kernel/ACPI/AML/Field.cpp
|
||||||
kernel/ACPI/AML/MiscObject.cpp
|
kernel/ACPI/AML/NamedObject.cpp
|
||||||
kernel/ACPI/AML/NameObject.cpp
|
kernel/ACPI/AML/Namespace.cpp
|
||||||
kernel/ACPI/AML/TermObject.cpp
|
kernel/ACPI/AML/Node.cpp
|
||||||
|
kernel/ACPI/AML/Scope.cpp
|
||||||
kernel/APIC.cpp
|
kernel/APIC.cpp
|
||||||
kernel/BootInfo.cpp
|
kernel/BootInfo.cpp
|
||||||
kernel/CPUID.cpp
|
kernel/CPUID.cpp
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <BAN/Vector.h>
|
#include <BAN/Vector.h>
|
||||||
|
#include <kernel/ACPI/AML/Namespace.h>
|
||||||
#include <kernel/ACPI/Headers.h>
|
#include <kernel/ACPI/Headers.h>
|
||||||
#include <kernel/Memory/Types.h>
|
#include <kernel/Memory/Types.h>
|
||||||
|
|
||||||
|
@ -32,6 +33,8 @@ namespace Kernel::ACPI
|
||||||
SDTHeader* as_header() { return (SDTHeader*)vaddr; }
|
SDTHeader* as_header() { return (SDTHeader*)vaddr; }
|
||||||
};
|
};
|
||||||
BAN::Vector<MappedPage> m_mapped_headers;
|
BAN::Vector<MappedPage> m_mapped_headers;
|
||||||
|
|
||||||
|
BAN::RefPtr<AML::Namespace> m_namespace;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <kernel/ACPI/Headers.h>
|
#include <kernel/ACPI/Headers.h>
|
||||||
|
#include <kernel/ACPI/AML/Namespace.h>
|
||||||
|
|
||||||
namespace Kernel::ACPI
|
namespace Kernel::ACPI
|
||||||
{
|
{
|
||||||
|
@ -10,7 +11,7 @@ namespace Kernel::ACPI
|
||||||
public:
|
public:
|
||||||
~AMLParser();
|
~AMLParser();
|
||||||
|
|
||||||
static AMLParser parse_table(const SDTHeader& header);
|
static BAN::RefPtr<AML::Namespace> parse_table(const SDTHeader& header);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
AMLParser();
|
AMLParser();
|
||||||
|
|
|
@ -0,0 +1,60 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <kernel/ACPI/AML/Bytes.h>
|
||||||
|
#include <kernel/ACPI/AML/Node.h>
|
||||||
|
#include <kernel/ACPI/AML/ParseContext.h>
|
||||||
|
#include <kernel/ACPI/AML/Pkg.h>
|
||||||
|
|
||||||
|
namespace Kernel::ACPI::AML
|
||||||
|
{
|
||||||
|
|
||||||
|
struct Buffer : public AML::Node
|
||||||
|
{
|
||||||
|
BAN::Vector<uint8_t> buffer;
|
||||||
|
|
||||||
|
Buffer() : AML::Node(Node::Type::Buffer) {}
|
||||||
|
|
||||||
|
static ParseResult parse(AML::ParseContext& context)
|
||||||
|
{
|
||||||
|
ASSERT(context.aml_data.size() >= 1);
|
||||||
|
ASSERT(static_cast<Byte>(context.aml_data[0]) == Byte::BufferOp);
|
||||||
|
context.aml_data = context.aml_data.slice(1);
|
||||||
|
|
||||||
|
auto buffer_pkg = AML::parse_pkg(context.aml_data);
|
||||||
|
if (!buffer_pkg.has_value())
|
||||||
|
return ParseResult::Failure;
|
||||||
|
|
||||||
|
auto buffer_context = context;
|
||||||
|
buffer_context.aml_data = buffer_pkg.value();
|
||||||
|
|
||||||
|
auto buffer_size_object = AML::parse_object(buffer_context);
|
||||||
|
if (!buffer_size_object.success())
|
||||||
|
return ParseResult::Failure;
|
||||||
|
|
||||||
|
auto buffer_size = buffer_size_object.node()->as_integer();
|
||||||
|
if (!buffer_size.has_value())
|
||||||
|
return ParseResult::Failure;
|
||||||
|
|
||||||
|
uint32_t actual_buffer_size = BAN::Math::max(buffer_size.value(), buffer_context.aml_data.size());
|
||||||
|
|
||||||
|
auto buffer = MUST(BAN::RefPtr<Buffer>::create());
|
||||||
|
MUST(buffer->buffer.resize(actual_buffer_size, 0));
|
||||||
|
for (uint32_t i = 0; i < buffer_context.aml_data.size(); i++)
|
||||||
|
buffer->buffer[i] = buffer_context.aml_data[i];
|
||||||
|
|
||||||
|
#if AML_DEBUG_LEVEL >= 2
|
||||||
|
buffer->debug_print(0);
|
||||||
|
AML_DEBUG_PRINTLN("");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return ParseResult(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void debug_print(int indent) const override
|
||||||
|
{
|
||||||
|
AML_DEBUG_PRINT_INDENT(indent);
|
||||||
|
AML_DEBUG_PRINT("Buffer ({} bytes)", buffer.size());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -1,196 +1,59 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <BAN/Formatter.h>
|
#include <stdint.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
|
namespace Kernel::ACPI::AML
|
||||||
{
|
{
|
||||||
extern size_t g_depth;
|
|
||||||
struct Indenter
|
enum class Byte
|
||||||
{
|
{
|
||||||
Indenter() { g_depth++; }
|
NullName = 0x00,
|
||||||
~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,
|
ZeroOp = 0x00,
|
||||||
OneOp = 0x01,
|
OneOp = 0x01,
|
||||||
OnesOp = 0xFF,
|
// 0x02 - 0x05
|
||||||
|
AliasOp = 0x06,
|
||||||
// ComputationalData
|
// 0x07
|
||||||
|
NameOp = 0x08,
|
||||||
|
// 0x09
|
||||||
BytePrefix = 0x0A,
|
BytePrefix = 0x0A,
|
||||||
WordPrefix = 0x0B,
|
WordPrefix = 0x0B,
|
||||||
DWordPrefix = 0x0C,
|
DWordPrefix = 0x0C,
|
||||||
StringPrefix = 0x0D,
|
StringPrefix = 0x0D,
|
||||||
QWordPrefix = 0x0E,
|
QWordPrefix = 0x0E,
|
||||||
|
// 0x0F
|
||||||
|
ScopeOp = 0x10,
|
||||||
BufferOp = 0x11,
|
BufferOp = 0x11,
|
||||||
ExtRevisionOp = 0x30,
|
|
||||||
|
|
||||||
// DataObject
|
|
||||||
PackageOp = 0x12,
|
PackageOp = 0x12,
|
||||||
VarPackageOp = 0x13,
|
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,
|
MethodOp = 0x14,
|
||||||
ExtMutexOp = 0x01,
|
ExternalOp = 0x15,
|
||||||
ExtEventOp = 0x02,
|
// 0x16 - 0x2D
|
||||||
ExtFieldOp = 0x81,
|
DualNamePrefix = 0x2E,
|
||||||
ExtDeviceOp = 0x82,
|
MultiNamePrefix = 0x2F,
|
||||||
ExtIndexFieldOp = 0x86,
|
// 0x30 - 0x39 DigitChar
|
||||||
|
// 0x3A - 0x40
|
||||||
// StatementOpcode
|
// 0x41 - 0x5A NameChar
|
||||||
BreakOp = 0xA5,
|
ExtOpPrefix = 0x5B,
|
||||||
BreakPointOp = 0xCC,
|
RootChar = 0x5C,
|
||||||
ContinueOp = 0x9F,
|
// 0x5D
|
||||||
ElseOp = 0xA1,
|
ParentPrefixChar = 0x5E,
|
||||||
IfOp = 0xA0,
|
// 0x5F NameChar
|
||||||
NoopOp = 0xA3,
|
Local0 = 0x60,
|
||||||
NotifyOp = 0x86,
|
Local1 = 0x61,
|
||||||
ReturnOp = 0xA4,
|
Local2 = 0x62,
|
||||||
WhileOp = 0xA2,
|
Local3 = 0x63,
|
||||||
ExtFatalOp = 0x32,
|
Local4 = 0x64,
|
||||||
ExtReleaseOp = 0x27,
|
Local5 = 0x65,
|
||||||
ExtResetOp = 0x26,
|
Local6 = 0x66,
|
||||||
ExtSignalOp = 0x24,
|
Local7 = 0x67,
|
||||||
ExtSleepOp = 0x22,
|
Arg0 = 0x68,
|
||||||
ExtStallOp = 0x21,
|
Arg1 = 0x69,
|
||||||
|
Arg2 = 0x6A,
|
||||||
// ExpressionOpcode
|
Arg3 = 0x6B,
|
||||||
//PackageOp = 0x12,
|
Arg4 = 0x6C,
|
||||||
//VarPackageOp = 0x13,
|
Arg5 = 0x6D,
|
||||||
//BufferOp = 0x11,
|
Arg6 = 0x6E,
|
||||||
|
// 0x6F
|
||||||
StoreOp = 0x70,
|
StoreOp = 0x70,
|
||||||
RefOfOp = 0x71,
|
RefOfOp = 0x71,
|
||||||
AddOp = 0x72,
|
AddOp = 0x72,
|
||||||
|
@ -203,20 +66,26 @@ namespace Kernel::ACPI::AML {
|
||||||
ShiftLeftOp = 0x79,
|
ShiftLeftOp = 0x79,
|
||||||
ShiftRightOp = 0x7A,
|
ShiftRightOp = 0x7A,
|
||||||
AndOp = 0x7B,
|
AndOp = 0x7B,
|
||||||
NAndOp = 0x7C,
|
NandOp = 0x7C,
|
||||||
OrOp = 0x7D,
|
OrOp = 0x7D,
|
||||||
NOrOp = 0x7E,
|
NorOp = 0x7E,
|
||||||
XOrOp = 0x7F,
|
XorOp = 0x7F,
|
||||||
NotOp = 0x80,
|
NotOp = 0x80,
|
||||||
FindSetLeftBitOp = 0x81,
|
FindSetLeftBitOp = 0x81,
|
||||||
FindSetRightBitOp = 0x82,
|
FindSetRightBitOp = 0x82,
|
||||||
DerefOfOp = 0x83,
|
DerefOfOp = 0x83,
|
||||||
ConcatResOp = 0x84,
|
ConcatResOp = 0x84,
|
||||||
ModOp = 0x85,
|
ModOp = 0x85,
|
||||||
|
NotifyOp = 0x86,
|
||||||
SizeOfOp = 0x87,
|
SizeOfOp = 0x87,
|
||||||
IndexOp = 0x88,
|
IndexOp = 0x88,
|
||||||
MatchOp = 0x89,
|
MatchOp = 0x89,
|
||||||
|
CreateDWordFieldOp = 0x8A,
|
||||||
|
CreateWordFieldOp = 0x8B,
|
||||||
|
CreateByteFieldOp = 0x8C,
|
||||||
|
CreateBitFieldOp = 0x8D,
|
||||||
ObjectTypeOp = 0x8E,
|
ObjectTypeOp = 0x8E,
|
||||||
|
CreateQWordFieldOp = 0x8F,
|
||||||
LAndOp = 0x90,
|
LAndOp = 0x90,
|
||||||
LOrOp = 0x91,
|
LOrOp = 0x91,
|
||||||
LNotOp = 0x92,
|
LNotOp = 0x92,
|
||||||
|
@ -227,39 +96,68 @@ namespace Kernel::ACPI::AML {
|
||||||
ToDecimalStringOp = 0x97,
|
ToDecimalStringOp = 0x97,
|
||||||
ToHexStringOp = 0x98,
|
ToHexStringOp = 0x98,
|
||||||
ToIntegerOp = 0x99,
|
ToIntegerOp = 0x99,
|
||||||
|
// 0x9A - 0x9B
|
||||||
ToStringOp = 0x9C,
|
ToStringOp = 0x9C,
|
||||||
CopyObjectOp = 0x9D,
|
CopyObjectOp = 0x9D,
|
||||||
MidOp = 0x9E,
|
MidOp = 0x9E,
|
||||||
ExtCondRefOfOp = 0x12,
|
ContinueOp = 0x9F,
|
||||||
ExtLoadTableOp = 0x1F,
|
IfOp = 0xA0,
|
||||||
ExtLoadOp = 0x20,
|
ElseOp = 0xA1,
|
||||||
ExtAcquireOp = 0x23,
|
WhileOp = 0xA2,
|
||||||
ExtWaitOp = 0x25,
|
NoopOp = 0xA3,
|
||||||
ExtFromBCDOp = 0x28,
|
ReturnOp = 0xA4,
|
||||||
ExtToBCDOp = 0x29,
|
BreakOp = 0xA5,
|
||||||
ExtTimerOp = 0x33,
|
// 0xA6 - 0xCB
|
||||||
|
BreakPointOp = 0xCC,
|
||||||
// LocalObj
|
// 0xCD - 0xFE
|
||||||
Local0Op = 0x60,
|
OnesOp = 0xFF,
|
||||||
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,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class ExtOp
|
||||||
|
{
|
||||||
|
MutexOp = 0x01,
|
||||||
|
EventOp = 0x02,
|
||||||
|
CondRefOfOp = 0x12,
|
||||||
|
CreateFieldOp = 0x13,
|
||||||
|
LoadTableOp = 0x1F,
|
||||||
|
LoadOp = 0x20,
|
||||||
|
StallOp = 0x21,
|
||||||
|
SleepOp = 0x22,
|
||||||
|
AcquireOp = 0x23,
|
||||||
|
SignalOp = 0x24,
|
||||||
|
WaitOp = 0x25,
|
||||||
|
ResetOp = 0x26,
|
||||||
|
ReleaseOp = 0x27,
|
||||||
|
FromBCDOp = 0x28,
|
||||||
|
ToBCDOp = 0x29,
|
||||||
|
RevisionOp = 0x30,
|
||||||
|
DebugOp = 0x31,
|
||||||
|
FatalOp = 0x32,
|
||||||
|
TimerOp = 0x33,
|
||||||
|
OpRegionOp = 0x80,
|
||||||
|
FieldOp = 0x81,
|
||||||
|
DeviceOp = 0x82,
|
||||||
|
ProcessorOp = 0x83,
|
||||||
|
PowerResOp = 0x84,
|
||||||
|
ThermalZoneOp = 0x85,
|
||||||
|
IndexFieldOp = 0x86,
|
||||||
|
BankFieldOp = 0x87,
|
||||||
|
DataRegionOp = 0x88,
|
||||||
|
};
|
||||||
|
|
||||||
|
static constexpr bool is_digit_char(uint8_t ch)
|
||||||
|
{
|
||||||
|
return '0' <= ch && ch <= '9';
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr bool is_lead_name_char(uint8_t ch)
|
||||||
|
{
|
||||||
|
return ('A' <= ch && ch <= 'Z') || ch == '_';
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr bool is_name_char(uint8_t ch)
|
||||||
|
{
|
||||||
|
return is_lead_name_char(ch) || is_digit_char(ch);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,102 +0,0 @@
|
||||||
#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;
|
|
||||||
struct Uninitialized {};
|
|
||||||
|
|
||||||
// PackageElement := DataRefObject | NameString
|
|
||||||
using PackageElement = BAN::Variant<BAN::UniqPtr<DataRefObject>, NameString, Uninitialized>;
|
|
||||||
|
|
||||||
// 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,52 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <kernel/ACPI/AML/ParseContext.h>
|
||||||
|
#include <kernel/ACPI/AML/Pkg.h>
|
||||||
|
#include <kernel/ACPI/AML/Scope.h>
|
||||||
|
|
||||||
|
namespace Kernel::ACPI::AML
|
||||||
|
{
|
||||||
|
|
||||||
|
struct Device : public AML::Scope
|
||||||
|
{
|
||||||
|
Device(NameSeg name) : Scope(name, Node::Type::Device) {}
|
||||||
|
|
||||||
|
static ParseResult parse(ParseContext& context)
|
||||||
|
{
|
||||||
|
ASSERT(context.aml_data.size() >= 2);
|
||||||
|
ASSERT(static_cast<AML::Byte>(context.aml_data[0]) == AML::Byte::ExtOpPrefix);
|
||||||
|
ASSERT(static_cast<AML::ExtOp>(context.aml_data[1]) == AML::ExtOp::DeviceOp);
|
||||||
|
context.aml_data = context.aml_data.slice(2);
|
||||||
|
|
||||||
|
auto device_pkg = AML::parse_pkg(context.aml_data);
|
||||||
|
if (!device_pkg.has_value())
|
||||||
|
return ParseResult::Failure;
|
||||||
|
|
||||||
|
auto name_string = AML::NameString::parse(device_pkg.value());
|
||||||
|
if (!name_string.has_value())
|
||||||
|
return ParseResult::Failure;
|
||||||
|
|
||||||
|
auto device = MUST(BAN::RefPtr<Device>::create(name_string->path.back()));
|
||||||
|
if (!context.root_namespace->add_named_object(context.scope.span(), name_string.value(), device))
|
||||||
|
return ParseResult::Failure;
|
||||||
|
|
||||||
|
return device->enter_context_and_parse_term_list(context, name_string.value(), device_pkg.value());
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void debug_print(int indent) const override
|
||||||
|
{
|
||||||
|
AML_DEBUG_PRINT_INDENT(indent);
|
||||||
|
AML_DEBUG_PRINT("Device ");
|
||||||
|
name.debug_print();
|
||||||
|
AML_DEBUG_PRINTLN(" {");
|
||||||
|
for (const auto& [name, object] : objects)
|
||||||
|
{
|
||||||
|
object->debug_print(indent + 1);
|
||||||
|
AML_DEBUG_PRINTLN("");
|
||||||
|
}
|
||||||
|
AML_DEBUG_PRINT_INDENT(indent);
|
||||||
|
AML_DEBUG_PRINT("}");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,89 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <kernel/ACPI/AML/NamedObject.h>
|
||||||
|
#include <kernel/ACPI/AML/ParseContext.h>
|
||||||
|
#include <kernel/ACPI/AML/Pkg.h>
|
||||||
|
#include <kernel/ACPI/AML/Region.h>
|
||||||
|
|
||||||
|
namespace Kernel::ACPI::AML
|
||||||
|
{
|
||||||
|
|
||||||
|
struct FieldRules
|
||||||
|
{
|
||||||
|
enum class AccessType
|
||||||
|
{
|
||||||
|
Any = 0,
|
||||||
|
Byte = 1,
|
||||||
|
Word = 2,
|
||||||
|
DWord = 3,
|
||||||
|
QWord = 4,
|
||||||
|
Buffer = 5,
|
||||||
|
};
|
||||||
|
AccessType access_type;
|
||||||
|
|
||||||
|
enum class LockRule
|
||||||
|
{
|
||||||
|
NoLock = 0,
|
||||||
|
Lock = 1,
|
||||||
|
};
|
||||||
|
LockRule lock_rule;
|
||||||
|
|
||||||
|
enum class UpdateRule
|
||||||
|
{
|
||||||
|
Preserve = 0,
|
||||||
|
WriteAsOnes = 1,
|
||||||
|
WriteAsZeros = 2,
|
||||||
|
};
|
||||||
|
UpdateRule update_rule;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct FieldElement : public NamedObject
|
||||||
|
{
|
||||||
|
uint64_t bit_offset;
|
||||||
|
uint32_t bit_count;
|
||||||
|
|
||||||
|
FieldRules access_rules;
|
||||||
|
|
||||||
|
OpRegion* op_region = nullptr;
|
||||||
|
|
||||||
|
FieldElement(NameSeg name, uint64_t bit_offset, uint32_t bit_count, FieldRules access_rules)
|
||||||
|
: NamedObject(Node::Type::FieldElement, name)
|
||||||
|
, bit_offset(bit_offset)
|
||||||
|
, bit_count(bit_count)
|
||||||
|
, access_rules(access_rules)
|
||||||
|
{}
|
||||||
|
|
||||||
|
void debug_print(int indent) const override;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Field
|
||||||
|
{
|
||||||
|
static ParseResult parse(ParseContext& context);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct IndexFieldElement : public NamedObject
|
||||||
|
{
|
||||||
|
uint64_t bit_offset;
|
||||||
|
uint32_t bit_count;
|
||||||
|
|
||||||
|
FieldRules access_rules;
|
||||||
|
|
||||||
|
FieldElement* index_element = nullptr;
|
||||||
|
FieldElement* data_element = nullptr;
|
||||||
|
|
||||||
|
IndexFieldElement(NameSeg name, uint64_t bit_offset, uint32_t bit_count, FieldRules access_rules)
|
||||||
|
: NamedObject(Node::Type::IndexFieldElement, name)
|
||||||
|
, bit_offset(bit_offset)
|
||||||
|
, bit_count(bit_count)
|
||||||
|
, access_rules(access_rules)
|
||||||
|
{}
|
||||||
|
|
||||||
|
void debug_print(int indent) const override;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct IndexField
|
||||||
|
{
|
||||||
|
static ParseResult parse(ParseContext& context);
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,92 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <BAN/Endianness.h>
|
||||||
|
#include <BAN/Optional.h>
|
||||||
|
#include <BAN/String.h>
|
||||||
|
#include <BAN/Vector.h>
|
||||||
|
#include <kernel/ACPI/AML/Bytes.h>
|
||||||
|
#include <kernel/ACPI/AML/Node.h>
|
||||||
|
#include <kernel/ACPI/AML/Utils.h>
|
||||||
|
|
||||||
|
namespace Kernel::ACPI::AML
|
||||||
|
{
|
||||||
|
|
||||||
|
struct Integer : public Node
|
||||||
|
{
|
||||||
|
static constexpr uint64_t Ones = -1;
|
||||||
|
uint64_t value;
|
||||||
|
|
||||||
|
Integer(uint64_t value) : Node(Node::Type::Integer), value(value) {}
|
||||||
|
|
||||||
|
BAN::Optional<uint64_t> as_integer() const override
|
||||||
|
{
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ParseResult parse(BAN::ConstByteSpan& aml_data)
|
||||||
|
{
|
||||||
|
switch (static_cast<AML::Byte>(aml_data[0]))
|
||||||
|
{
|
||||||
|
case AML::Byte::ZeroOp:
|
||||||
|
aml_data = aml_data.slice(1);
|
||||||
|
return ParseResult(MUST(BAN::RefPtr<Integer>::create(0)));
|
||||||
|
case AML::Byte::OneOp:
|
||||||
|
aml_data = aml_data.slice(1);
|
||||||
|
return ParseResult(MUST(BAN::RefPtr<Integer>::create(1)));
|
||||||
|
case AML::Byte::OnesOp:
|
||||||
|
aml_data = aml_data.slice(1);
|
||||||
|
return ParseResult(MUST(BAN::RefPtr<Integer>::create(Ones)));
|
||||||
|
case AML::Byte::BytePrefix:
|
||||||
|
{
|
||||||
|
if (aml_data.size() < 2)
|
||||||
|
return ParseResult::Failure;
|
||||||
|
uint8_t value = aml_data[1];
|
||||||
|
aml_data = aml_data.slice(2);
|
||||||
|
return ParseResult(MUST(BAN::RefPtr<Integer>::create(value)));
|
||||||
|
}
|
||||||
|
case AML::Byte::WordPrefix:
|
||||||
|
{
|
||||||
|
if (aml_data.size() < 3)
|
||||||
|
return ParseResult::Failure;
|
||||||
|
uint16_t value = BAN::little_endian_to_host<uint16_t>(
|
||||||
|
*reinterpret_cast<const uint16_t*>(&aml_data[1])
|
||||||
|
);
|
||||||
|
aml_data = aml_data.slice(3);
|
||||||
|
return ParseResult(MUST(BAN::RefPtr<Integer>::create(value)));
|
||||||
|
}
|
||||||
|
case AML::Byte::DWordPrefix:
|
||||||
|
{
|
||||||
|
if (aml_data.size() < 5)
|
||||||
|
return ParseResult::Failure;
|
||||||
|
uint32_t value = BAN::little_endian_to_host<uint32_t>(
|
||||||
|
*reinterpret_cast<const uint32_t*>(&aml_data[1])
|
||||||
|
);
|
||||||
|
aml_data = aml_data.slice(5);
|
||||||
|
return ParseResult(MUST(BAN::RefPtr<Integer>::create(value)));
|
||||||
|
}
|
||||||
|
case AML::Byte::QWordPrefix:
|
||||||
|
{
|
||||||
|
if (aml_data.size() < 9)
|
||||||
|
return ParseResult::Failure;
|
||||||
|
uint64_t value = BAN::little_endian_to_host<uint64_t>(
|
||||||
|
*reinterpret_cast<const uint64_t*>(&aml_data[1])
|
||||||
|
);
|
||||||
|
aml_data = aml_data.slice(9);
|
||||||
|
return ParseResult(MUST(BAN::RefPtr<Integer>::create(value)));
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
ASSERT_NOT_REACHED();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void debug_print(int indent) const override
|
||||||
|
{
|
||||||
|
AML_DEBUG_PRINT_INDENT(indent);
|
||||||
|
if (value == Ones)
|
||||||
|
AML_DEBUG_PRINT("Ones");
|
||||||
|
else
|
||||||
|
AML_DEBUG_PRINT("0x{H}", value);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,78 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <kernel/ACPI/AML/Bytes.h>
|
||||||
|
#include <kernel/ACPI/AML/NamedObject.h>
|
||||||
|
#include <kernel/ACPI/AML/ParseContext.h>
|
||||||
|
#include <kernel/ACPI/AML/Pkg.h>
|
||||||
|
|
||||||
|
namespace Kernel::ACPI::AML
|
||||||
|
{
|
||||||
|
|
||||||
|
struct Method : public AML::NamedObject
|
||||||
|
{
|
||||||
|
uint8_t arg_count;
|
||||||
|
bool serialized;
|
||||||
|
uint8_t sync_level;
|
||||||
|
|
||||||
|
BAN::ConstByteSpan term_list;
|
||||||
|
|
||||||
|
Method(AML::NameSeg name, uint8_t arg_count, bool serialized, uint8_t sync_level, BAN::ConstByteSpan term_list)
|
||||||
|
: AML::NamedObject(Node::Type::Method, name)
|
||||||
|
, arg_count(arg_count)
|
||||||
|
, serialized(serialized)
|
||||||
|
, sync_level(sync_level)
|
||||||
|
, term_list(term_list)
|
||||||
|
{}
|
||||||
|
|
||||||
|
static ParseResult parse(AML::ParseContext& context)
|
||||||
|
{
|
||||||
|
ASSERT(context.aml_data.size() >= 1);
|
||||||
|
ASSERT(static_cast<Byte>(context.aml_data[0]) == Byte::MethodOp);
|
||||||
|
context.aml_data = context.aml_data.slice(1);
|
||||||
|
|
||||||
|
auto method_pkg = AML::parse_pkg(context.aml_data);
|
||||||
|
if (!method_pkg.has_value())
|
||||||
|
return ParseResult::Failure;
|
||||||
|
|
||||||
|
auto name_string = AML::NameString::parse(method_pkg.value());
|
||||||
|
if (!name_string.has_value())
|
||||||
|
return ParseResult::Failure;
|
||||||
|
|
||||||
|
if (method_pkg->size() < 1)
|
||||||
|
return ParseResult::Failure;
|
||||||
|
auto method_flags = method_pkg.value()[0];
|
||||||
|
method_pkg = method_pkg.value().slice(1);
|
||||||
|
|
||||||
|
auto method = MUST(BAN::RefPtr<Method>::create(
|
||||||
|
name_string.value().path.back(),
|
||||||
|
method_flags & 0x07,
|
||||||
|
(method_flags >> 3) & 0x01,
|
||||||
|
method_flags >> 4,
|
||||||
|
method_pkg.value()
|
||||||
|
));
|
||||||
|
|
||||||
|
if (!context.root_namespace->add_named_object(context.scope.span(), name_string.value(), method))
|
||||||
|
return ParseResult::Failure;
|
||||||
|
|
||||||
|
#if AML_DEBUG_LEVEL >= 2
|
||||||
|
method->debug_print(0);
|
||||||
|
AML_DEBUG_PRINTLN("");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return ParseResult::Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void debug_print(int indent) const override
|
||||||
|
{
|
||||||
|
AML_DEBUG_PRINT_INDENT(indent);
|
||||||
|
AML_DEBUG_PRINT("Method ");
|
||||||
|
name.debug_print();
|
||||||
|
AML_DEBUG_PRINTLN("({} args, {}Serialized, 0x{H}) {", arg_count, serialized ? "" : "Not", sync_level);
|
||||||
|
AML_DEBUG_PRINT_INDENT(indent + 1);
|
||||||
|
AML_DEBUG_PRINTLN("TermList: {} bytes", term_list.size());
|
||||||
|
AML_DEBUG_PRINT_INDENT(indent);
|
||||||
|
AML_DEBUG_PRINT("}");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -1,56 +0,0 @@
|
||||||
#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,62 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <kernel/ACPI/AML/Bytes.h>
|
||||||
|
#include <kernel/ACPI/AML/NamedObject.h>
|
||||||
|
#include <kernel/ACPI/AML/ParseContext.h>
|
||||||
|
|
||||||
|
namespace Kernel::ACPI::AML
|
||||||
|
{
|
||||||
|
|
||||||
|
struct Mutex : public AML::NamedObject
|
||||||
|
{
|
||||||
|
uint8_t sync_level;
|
||||||
|
|
||||||
|
Mutex(NameSeg name, uint8_t sync_level)
|
||||||
|
: NamedObject(Node::Type::Mutex, name)
|
||||||
|
, sync_level(sync_level)
|
||||||
|
{}
|
||||||
|
|
||||||
|
static ParseResult parse(ParseContext& context)
|
||||||
|
{
|
||||||
|
ASSERT(context.aml_data.size() >= 2);
|
||||||
|
ASSERT(static_cast<AML::Byte>(context.aml_data[0]) == AML::Byte::ExtOpPrefix);
|
||||||
|
ASSERT(static_cast<AML::ExtOp>(context.aml_data[1]) == AML::ExtOp::MutexOp);
|
||||||
|
context.aml_data = context.aml_data.slice(2);
|
||||||
|
|
||||||
|
auto name = NameString::parse(context.aml_data);
|
||||||
|
if (!name.has_value())
|
||||||
|
return ParseResult::Failure;
|
||||||
|
|
||||||
|
if (context.aml_data.size() < 1)
|
||||||
|
return ParseResult::Failure;
|
||||||
|
auto sync_level = context.aml_data[0];
|
||||||
|
context.aml_data = context.aml_data.slice(1);
|
||||||
|
|
||||||
|
if (sync_level & 0xF0)
|
||||||
|
{
|
||||||
|
AML_ERROR("Invalid sync level {}", sync_level);
|
||||||
|
return ParseResult::Failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto mutex = MUST(BAN::RefPtr<Mutex>::create(name->path.back(), sync_level));
|
||||||
|
if (!context.root_namespace->add_named_object(context.scope.span(), name.value(), mutex))
|
||||||
|
return ParseResult::Failure;
|
||||||
|
|
||||||
|
#if AML_DEBUG_LEVEL >= 2
|
||||||
|
mutex->debug_print(0);
|
||||||
|
AML_DEBUG_PRINTLN("");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return ParseResult::Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void debug_print(int indent) const override
|
||||||
|
{
|
||||||
|
AML_DEBUG_PRINT_INDENT(indent);
|
||||||
|
AML_DEBUG_PRINT("Mutex ");
|
||||||
|
name.debug_print();
|
||||||
|
AML_DEBUG_PRINT(" (SyncLevel: {})", sync_level);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -1,46 +0,0 @@
|
||||||
#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,28 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <BAN/HashMap.h>
|
||||||
|
#include <kernel/ACPI/AML/Names.h>
|
||||||
|
|
||||||
|
namespace Kernel::ACPI::AML
|
||||||
|
{
|
||||||
|
|
||||||
|
struct NamedObject : public Node
|
||||||
|
{
|
||||||
|
NameSeg name;
|
||||||
|
|
||||||
|
NamedObject(Node::Type type, NameSeg name) : Node(type), name(name) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Name : public NamedObject
|
||||||
|
{
|
||||||
|
BAN::RefPtr<AML::Node> object;
|
||||||
|
|
||||||
|
Name(NameSeg name, BAN::RefPtr<AML::Node> object)
|
||||||
|
: NamedObject(Node::Type::Name, name), object(BAN::move(object))
|
||||||
|
{}
|
||||||
|
|
||||||
|
static ParseResult parse(ParseContext& context);
|
||||||
|
virtual void debug_print(int indent) const override;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,157 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <BAN/Optional.h>
|
||||||
|
#include <BAN/String.h>
|
||||||
|
#include <BAN/Vector.h>
|
||||||
|
#include <kernel/ACPI/AML/Bytes.h>
|
||||||
|
#include <kernel/ACPI/AML/Node.h>
|
||||||
|
#include <kernel/ACPI/AML/Utils.h>
|
||||||
|
|
||||||
|
namespace Kernel::ACPI::AML
|
||||||
|
{
|
||||||
|
|
||||||
|
struct NameSeg
|
||||||
|
{
|
||||||
|
union {
|
||||||
|
char chars[4];
|
||||||
|
uint32_t u32;
|
||||||
|
};
|
||||||
|
|
||||||
|
NameSeg() = default;
|
||||||
|
|
||||||
|
NameSeg(BAN::StringView name)
|
||||||
|
{
|
||||||
|
ASSERT(name.size() <= 4);
|
||||||
|
for (size_t i = 0; i < name.size(); i++)
|
||||||
|
chars[i] = static_cast<char>(name[i]);
|
||||||
|
for (size_t i = name.size(); i < 4; i++)
|
||||||
|
chars[i] = '_';
|
||||||
|
}
|
||||||
|
|
||||||
|
NameSeg(BAN::ConstByteSpan& aml_data)
|
||||||
|
{
|
||||||
|
ASSERT(aml_data.size() >= 4);
|
||||||
|
for (size_t i = 0; i < 4; i++)
|
||||||
|
chars[i] = static_cast<char>(aml_data[i]);
|
||||||
|
aml_data = aml_data.slice(4);
|
||||||
|
}
|
||||||
|
|
||||||
|
static BAN::Optional<NameSeg> parse(BAN::ConstByteSpan& aml_data)
|
||||||
|
{
|
||||||
|
if (aml_data.size() < 4)
|
||||||
|
return {};
|
||||||
|
|
||||||
|
if (!is_lead_name_char(aml_data[0])
|
||||||
|
|| !is_name_char(aml_data[1])
|
||||||
|
|| !is_name_char(aml_data[2])
|
||||||
|
|| !is_name_char(aml_data[3]))
|
||||||
|
return {};
|
||||||
|
|
||||||
|
return NameSeg(aml_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr bool operator==(const NameSeg& other) const
|
||||||
|
{
|
||||||
|
return u32 == other.u32;
|
||||||
|
}
|
||||||
|
|
||||||
|
void debug_print() const
|
||||||
|
{
|
||||||
|
size_t len = 4;
|
||||||
|
while (len > 0 && chars[len - 1] == '_')
|
||||||
|
len--;
|
||||||
|
for (size_t i = 0; i < len; i++)
|
||||||
|
AML_DEBUG_PUTC(chars[i]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct NameString
|
||||||
|
{
|
||||||
|
BAN::String prefix;
|
||||||
|
BAN::Vector<NameSeg> path;
|
||||||
|
|
||||||
|
static BAN::Optional<NameString> parse(BAN::ConstByteSpan& aml_data)
|
||||||
|
{
|
||||||
|
if (aml_data.size() == 0)
|
||||||
|
return {};
|
||||||
|
|
||||||
|
NameString result;
|
||||||
|
|
||||||
|
if (static_cast<AML::Byte>(aml_data[0]) == AML::Byte::RootChar)
|
||||||
|
{
|
||||||
|
MUST(result.prefix.push_back('\\'));
|
||||||
|
aml_data = aml_data.slice(1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
while (aml_data.size() > 0 && static_cast<AML::Byte>(aml_data[0]) == AML::Byte::ParentPrefixChar)
|
||||||
|
{
|
||||||
|
MUST(result.prefix.push_back(aml_data[0]));
|
||||||
|
aml_data = aml_data.slice(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (aml_data.size() == 0)
|
||||||
|
return {};
|
||||||
|
|
||||||
|
size_t name_count = 1;
|
||||||
|
switch (static_cast<AML::Byte>(aml_data[0]))
|
||||||
|
{
|
||||||
|
case AML::Byte::NullName:
|
||||||
|
name_count = 0;
|
||||||
|
aml_data = aml_data.slice(1);
|
||||||
|
break;
|
||||||
|
case AML::Byte::DualNamePrefix:
|
||||||
|
name_count = 2;
|
||||||
|
aml_data = aml_data.slice(1);
|
||||||
|
break;
|
||||||
|
case AML::Byte::MultiNamePrefix:
|
||||||
|
if (aml_data.size() < 2)
|
||||||
|
return {};
|
||||||
|
name_count = aml_data[1];
|
||||||
|
aml_data = aml_data.slice(2);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < name_count; i++)
|
||||||
|
{
|
||||||
|
auto name_seg = NameSeg::parse(aml_data);
|
||||||
|
if (!name_seg.has_value())
|
||||||
|
return {};
|
||||||
|
MUST(result.path.push_back(name_seg.release_value()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void debug_print() const
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < prefix.size(); i++)
|
||||||
|
AML_DEBUG_PUTC(prefix[i]);
|
||||||
|
if (!path.empty())
|
||||||
|
path.front().debug_print();
|
||||||
|
for (size_t i = 1; i < path.size(); i++)
|
||||||
|
{
|
||||||
|
AML_DEBUG_PUTC('.');
|
||||||
|
path[i].debug_print();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace BAN
|
||||||
|
{
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct hash<Kernel::ACPI::AML::NameSeg>
|
||||||
|
{
|
||||||
|
constexpr hash_t operator()(Kernel::ACPI::AML::NameSeg name) const
|
||||||
|
{
|
||||||
|
return hash<uint32_t>()(name.u32);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <kernel/ACPI/AML/Scope.h>
|
||||||
|
|
||||||
|
namespace Kernel::ACPI::AML
|
||||||
|
{
|
||||||
|
|
||||||
|
struct Namespace : public AML::Scope
|
||||||
|
{
|
||||||
|
Namespace() : AML::Scope(NameSeg("\\"sv)) {}
|
||||||
|
|
||||||
|
static BAN::RefPtr<Namespace> parse(BAN::ConstByteSpan aml);
|
||||||
|
|
||||||
|
BAN::Optional<BAN::Vector<AML::NameSeg>> resolve_path(BAN::Span<const AML::NameSeg> parsing_scope, const AML::NameString& relative_path);
|
||||||
|
|
||||||
|
// Find an object in the namespace. Returns nullptr if the object is not found.
|
||||||
|
BAN::RefPtr<NamedObject> find_object(BAN::Span<const AML::NameSeg> parsing_scope, const AML::NameString& relative_path);
|
||||||
|
|
||||||
|
// Add an object to the namespace. Returns false if the parent object could not be added.
|
||||||
|
bool add_named_object(BAN::Span<const AML::NameSeg> parsing_scope, const AML::NameString& object_path, BAN::RefPtr<NamedObject> object);
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,69 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <BAN/ByteSpan.h>
|
||||||
|
#include <BAN/Optional.h>
|
||||||
|
#include <BAN/RefPtr.h>
|
||||||
|
#include <BAN/Vector.h>
|
||||||
|
|
||||||
|
namespace Kernel::ACPI::AML
|
||||||
|
{
|
||||||
|
|
||||||
|
struct Node : public BAN::RefCounted<Node>
|
||||||
|
{
|
||||||
|
enum class Type
|
||||||
|
{
|
||||||
|
Buffer,
|
||||||
|
Device,
|
||||||
|
FieldElement,
|
||||||
|
IndexFieldElement,
|
||||||
|
Integer,
|
||||||
|
Method,
|
||||||
|
Mutex,
|
||||||
|
Name,
|
||||||
|
OpRegion,
|
||||||
|
Package,
|
||||||
|
Processor,
|
||||||
|
Scope,
|
||||||
|
String,
|
||||||
|
};
|
||||||
|
const Type type;
|
||||||
|
|
||||||
|
Node(Type type) : type(type) {}
|
||||||
|
virtual ~Node() = default;
|
||||||
|
|
||||||
|
virtual bool is_scope() const { return false; }
|
||||||
|
virtual BAN::Optional<uint64_t> as_integer() const { return {}; }
|
||||||
|
|
||||||
|
virtual void debug_print(int indent) const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ParseContext;
|
||||||
|
struct ParseResult
|
||||||
|
{
|
||||||
|
static ParseResult Failure;
|
||||||
|
static ParseResult Success;
|
||||||
|
|
||||||
|
enum class Result
|
||||||
|
{
|
||||||
|
Success,
|
||||||
|
Failure,
|
||||||
|
};
|
||||||
|
|
||||||
|
ParseResult(Result success) : m_result(success) {}
|
||||||
|
ParseResult(BAN::RefPtr<Node> node) : m_result(Result::Success), m_node(BAN::move(node)) { ASSERT(m_node); }
|
||||||
|
|
||||||
|
bool success() const { return m_result == Result::Success; }
|
||||||
|
|
||||||
|
BAN::RefPtr<Node> node()
|
||||||
|
{
|
||||||
|
ASSERT(m_node);
|
||||||
|
return m_node;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Result m_result = Result::Failure;
|
||||||
|
BAN::RefPtr<Node> m_node;
|
||||||
|
};
|
||||||
|
ParseResult parse_object(ParseContext& context);
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,66 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <kernel/ACPI/AML/Bytes.h>
|
||||||
|
#include <kernel/ACPI/AML/Node.h>
|
||||||
|
#include <kernel/ACPI/AML/ParseContext.h>
|
||||||
|
#include <kernel/ACPI/AML/Pkg.h>
|
||||||
|
|
||||||
|
namespace Kernel::ACPI::AML
|
||||||
|
{
|
||||||
|
|
||||||
|
struct Package : public AML::Node
|
||||||
|
{
|
||||||
|
BAN::Vector<BAN::RefPtr<AML::Node>> elements;
|
||||||
|
|
||||||
|
Package() : Node(Node::Type::Package) {}
|
||||||
|
|
||||||
|
static ParseResult parse(AML::ParseContext& context)
|
||||||
|
{
|
||||||
|
ASSERT(context.aml_data.size() >= 1);
|
||||||
|
ASSERT(static_cast<Byte>(context.aml_data[0]) == Byte::PackageOp);
|
||||||
|
context.aml_data = context.aml_data.slice(1);
|
||||||
|
|
||||||
|
auto package_pkg = AML::parse_pkg(context.aml_data);
|
||||||
|
if (!package_pkg.has_value())
|
||||||
|
return ParseResult::Failure;
|
||||||
|
|
||||||
|
auto package_context = context;
|
||||||
|
package_context.aml_data = package_pkg.value();
|
||||||
|
|
||||||
|
if (package_pkg->size() < 1)
|
||||||
|
return ParseResult::Failure;
|
||||||
|
uint8_t num_elements = package_context.aml_data[0];
|
||||||
|
package_context.aml_data = package_context.aml_data.slice(1);
|
||||||
|
|
||||||
|
BAN::Vector<BAN::RefPtr<AML::Node>> elements;
|
||||||
|
while (elements.size() < num_elements && package_context.aml_data.size() > 0)
|
||||||
|
{
|
||||||
|
auto element_result = AML::parse_object(package_context);
|
||||||
|
if (!element_result.success())
|
||||||
|
return ParseResult::Failure;
|
||||||
|
MUST(elements.push_back(element_result.node()));
|
||||||
|
}
|
||||||
|
while (elements.size() < num_elements)
|
||||||
|
MUST(elements.push_back(BAN::RefPtr<AML::Node>()));
|
||||||
|
|
||||||
|
auto package = MUST(BAN::RefPtr<Package>::create());
|
||||||
|
package->elements = BAN::move(elements);
|
||||||
|
return ParseResult(package);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void debug_print(int indent) const override
|
||||||
|
{
|
||||||
|
AML_DEBUG_PRINT_INDENT(indent);
|
||||||
|
AML_DEBUG_PRINT("Package {");
|
||||||
|
AML_DEBUG_PRINTLN("");
|
||||||
|
for (const auto& element : elements)
|
||||||
|
{
|
||||||
|
element->debug_print(indent + 1);
|
||||||
|
AML_DEBUG_PRINTLN("");
|
||||||
|
}
|
||||||
|
AML_DEBUG_PRINT_INDENT(indent);
|
||||||
|
AML_DEBUG_PRINT("}");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -1,36 +0,0 @@
|
||||||
#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,18 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <BAN/ByteSpan.h>
|
||||||
|
#include <BAN/Vector.h>
|
||||||
|
#include <kernel/ACPI/AML/NamedObject.h>
|
||||||
|
#include <kernel/ACPI/AML/Namespace.h>
|
||||||
|
|
||||||
|
namespace Kernel::ACPI::AML
|
||||||
|
{
|
||||||
|
|
||||||
|
struct ParseContext
|
||||||
|
{
|
||||||
|
BAN::ConstByteSpan aml_data;
|
||||||
|
BAN::Vector<AML::NameSeg> scope;
|
||||||
|
struct Namespace* root_namespace;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,51 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <BAN/ByteSpan.h>
|
||||||
|
#include <BAN/Optional.h>
|
||||||
|
|
||||||
|
namespace Kernel::ACPI::AML
|
||||||
|
{
|
||||||
|
|
||||||
|
static BAN::Optional<uint32_t> parse_pkg_length(BAN::ConstByteSpan aml_data)
|
||||||
|
{
|
||||||
|
if (aml_data.size() < 1)
|
||||||
|
return {};
|
||||||
|
|
||||||
|
uint8_t lead_byte = aml_data[0];
|
||||||
|
if ((lead_byte & 0xC0) && (lead_byte & 0x30))
|
||||||
|
return {};
|
||||||
|
|
||||||
|
uint32_t pkg_length = lead_byte & 0x3F;
|
||||||
|
uint8_t byte_count = (lead_byte >> 6) + 1;
|
||||||
|
|
||||||
|
if (aml_data.size() < byte_count)
|
||||||
|
return {};
|
||||||
|
|
||||||
|
for (uint8_t i = 1; i < byte_count; i++)
|
||||||
|
pkg_length |= aml_data[i] << (i * 8 - 4);
|
||||||
|
|
||||||
|
return pkg_length;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void trim_pkg_length(BAN::ConstByteSpan& aml_data)
|
||||||
|
{
|
||||||
|
ASSERT(aml_data.size() >= 1);
|
||||||
|
uint8_t byte_count = (aml_data[0] >> 6) + 1;
|
||||||
|
aml_data = aml_data.slice(byte_count);
|
||||||
|
}
|
||||||
|
|
||||||
|
static BAN::Optional<BAN::ConstByteSpan> parse_pkg(BAN::ConstByteSpan& aml_data)
|
||||||
|
{
|
||||||
|
auto pkg_length = parse_pkg_length(aml_data);
|
||||||
|
if (!pkg_length.has_value())
|
||||||
|
return {};
|
||||||
|
|
||||||
|
auto result = aml_data.slice(0, pkg_length.value());
|
||||||
|
trim_pkg_length(result);
|
||||||
|
|
||||||
|
aml_data = aml_data.slice(pkg_length.value());
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,71 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <BAN/Endianness.h>
|
||||||
|
#include <kernel/ACPI/AML/Bytes.h>
|
||||||
|
#include <kernel/ACPI/AML/ParseContext.h>
|
||||||
|
#include <kernel/ACPI/AML/Pkg.h>
|
||||||
|
#include <kernel/ACPI/AML/Scope.h>
|
||||||
|
|
||||||
|
namespace Kernel::ACPI::AML
|
||||||
|
{
|
||||||
|
|
||||||
|
struct Processor : public AML::Scope
|
||||||
|
{
|
||||||
|
uint8_t id;
|
||||||
|
uint32_t pblk_addr;
|
||||||
|
uint8_t pblk_len;
|
||||||
|
|
||||||
|
Processor(NameSeg name, uint8_t id, uint32_t pblk_addr, uint8_t pblk_len)
|
||||||
|
: Scope(name, Node::Type::Processor)
|
||||||
|
, id(id)
|
||||||
|
, pblk_addr(pblk_addr)
|
||||||
|
, pblk_len(pblk_len)
|
||||||
|
{}
|
||||||
|
|
||||||
|
static ParseResult parse(ParseContext& context)
|
||||||
|
{
|
||||||
|
ASSERT(context.aml_data.size() >= 2);
|
||||||
|
ASSERT(static_cast<AML::Byte>(context.aml_data[0]) == AML::Byte::ExtOpPrefix);
|
||||||
|
ASSERT(static_cast<AML::ExtOp>(context.aml_data[1]) == AML::ExtOp::ProcessorOp);
|
||||||
|
context.aml_data = context.aml_data.slice(2);
|
||||||
|
|
||||||
|
auto processor_pkg = AML::parse_pkg(context.aml_data);
|
||||||
|
if (!processor_pkg.has_value())
|
||||||
|
return ParseResult::Failure;
|
||||||
|
|
||||||
|
auto name = NameString::parse(processor_pkg.value());
|
||||||
|
if (!name.has_value())
|
||||||
|
return ParseResult::Failure;
|
||||||
|
|
||||||
|
if (processor_pkg->size() < 1)
|
||||||
|
return ParseResult::Failure;
|
||||||
|
uint8_t id = processor_pkg.value()[0];
|
||||||
|
processor_pkg = processor_pkg->slice(1);
|
||||||
|
|
||||||
|
if (processor_pkg->size() < 4)
|
||||||
|
return ParseResult::Failure;
|
||||||
|
uint32_t pblk_addr = BAN::little_endian_to_host<uint32_t>(*reinterpret_cast<const uint32_t*>(processor_pkg->data()));
|
||||||
|
processor_pkg = processor_pkg->slice(4);
|
||||||
|
|
||||||
|
if (processor_pkg->size() < 1)
|
||||||
|
return ParseResult::Failure;
|
||||||
|
uint8_t pblk_len = processor_pkg.value()[0];
|
||||||
|
processor_pkg = processor_pkg->slice(1);
|
||||||
|
|
||||||
|
auto processor = MUST(BAN::RefPtr<Processor>::create(name->path.back(), id, pblk_addr, pblk_len));
|
||||||
|
if (!context.root_namespace->add_named_object(context.scope.span(), name.value(), processor))
|
||||||
|
return ParseResult::Failure;
|
||||||
|
|
||||||
|
return processor->enter_context_and_parse_term_list(context, name.value(), processor_pkg.value());
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void debug_print(int indent) const override
|
||||||
|
{
|
||||||
|
AML_DEBUG_PRINT_INDENT(indent);
|
||||||
|
AML_DEBUG_PRINT("Processor ");
|
||||||
|
name.debug_print();
|
||||||
|
AML_DEBUG_PRINT(" (ID: {}, PBlkAddr: 0x{H}, PBlkLen: {})", id, pblk_addr, pblk_len);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,114 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <kernel/ACPI/AML/NamedObject.h>
|
||||||
|
#include <kernel/ACPI/AML/Namespace.h>
|
||||||
|
#include <kernel/ACPI/AML/ParseContext.h>
|
||||||
|
|
||||||
|
namespace Kernel::ACPI::AML
|
||||||
|
{
|
||||||
|
|
||||||
|
struct OpRegion : public NamedObject
|
||||||
|
{
|
||||||
|
enum class RegionSpace
|
||||||
|
{
|
||||||
|
SystemMemory = 0,
|
||||||
|
SystemIO = 1,
|
||||||
|
PCIConfig = 2,
|
||||||
|
EmbeddedController = 3,
|
||||||
|
SMBus = 4,
|
||||||
|
SystemCMOS = 5,
|
||||||
|
PCIBarTarget = 6,
|
||||||
|
IPMI = 7,
|
||||||
|
GeneralPurposeIO = 8,
|
||||||
|
GenericSerialBus = 9,
|
||||||
|
PCC = 10,
|
||||||
|
};
|
||||||
|
RegionSpace space;
|
||||||
|
uint64_t offset;
|
||||||
|
uint64_t length;
|
||||||
|
|
||||||
|
OpRegion(NameSeg name, RegionSpace space, uint64_t offset, uint64_t length)
|
||||||
|
: NamedObject(Node::Type::OpRegion, name), space(space), offset(offset), length(length)
|
||||||
|
{}
|
||||||
|
|
||||||
|
static ParseResult parse(AML::ParseContext& context)
|
||||||
|
{
|
||||||
|
ASSERT(context.aml_data.size() > 2);
|
||||||
|
ASSERT(static_cast<Byte>(context.aml_data[0]) == Byte::ExtOpPrefix);
|
||||||
|
ASSERT(static_cast<ExtOp>(context.aml_data[1]) == ExtOp::OpRegionOp);
|
||||||
|
context.aml_data = context.aml_data.slice(2);
|
||||||
|
|
||||||
|
auto name = NameString::parse(context.aml_data);
|
||||||
|
if (!name.has_value())
|
||||||
|
return ParseResult::Failure;
|
||||||
|
|
||||||
|
if (context.aml_data.size() < 1)
|
||||||
|
return ParseResult::Failure;
|
||||||
|
auto region_space = static_cast<RegionSpace>(context.aml_data[0]);
|
||||||
|
context.aml_data = context.aml_data.slice(1);
|
||||||
|
|
||||||
|
auto offset_result = AML::parse_object(context);
|
||||||
|
if (!offset_result.success())
|
||||||
|
return ParseResult::Failure;
|
||||||
|
auto offset = offset_result.node()->as_integer();
|
||||||
|
if (!offset.has_value())
|
||||||
|
{
|
||||||
|
AML_ERROR("OpRegion offset must be an integer");
|
||||||
|
return ParseResult::Failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto length_result = AML::parse_object(context);
|
||||||
|
if (!length_result.success())
|
||||||
|
return ParseResult::Failure;
|
||||||
|
auto length = length_result.node()->as_integer();
|
||||||
|
if (!length.has_value())
|
||||||
|
{
|
||||||
|
AML_ERROR("OpRegion length must be an integer");
|
||||||
|
return ParseResult::Failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto op_region = MUST(BAN::RefPtr<OpRegion>::create(
|
||||||
|
name->path.back(),
|
||||||
|
region_space,
|
||||||
|
offset.value(),
|
||||||
|
length.value()
|
||||||
|
));
|
||||||
|
|
||||||
|
if (!context.root_namespace->add_named_object(context.scope.span(), name.value(), op_region))
|
||||||
|
return ParseResult::Failure;
|
||||||
|
|
||||||
|
#if AML_DEBUG_LEVEL >= 2
|
||||||
|
op_region->debug_print(0);
|
||||||
|
AML_DEBUG_PRINTLN("");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return ParseResult::Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void debug_print(int indent) const override
|
||||||
|
{
|
||||||
|
BAN::StringView region_space_name;
|
||||||
|
switch (space)
|
||||||
|
{
|
||||||
|
case RegionSpace::SystemMemory: region_space_name = "SystemMemory"sv; break;
|
||||||
|
case RegionSpace::SystemIO: region_space_name = "SystemIO"sv; break;
|
||||||
|
case RegionSpace::PCIConfig: region_space_name = "PCIConfig"sv; break;
|
||||||
|
case RegionSpace::EmbeddedController: region_space_name = "EmbeddedController"sv; break;
|
||||||
|
case RegionSpace::SMBus: region_space_name = "SMBus"sv; break;
|
||||||
|
case RegionSpace::SystemCMOS: region_space_name = "SystemCMOS"sv; break;
|
||||||
|
case RegionSpace::PCIBarTarget: region_space_name = "PCIBarTarget"sv; break;
|
||||||
|
case RegionSpace::IPMI: region_space_name = "IPMI"sv; break;
|
||||||
|
case RegionSpace::GeneralPurposeIO: region_space_name = "GeneralPurposeIO"sv; break;
|
||||||
|
case RegionSpace::GenericSerialBus: region_space_name = "GenericSerialBus"sv; break;
|
||||||
|
case RegionSpace::PCC: region_space_name = "PCC"sv; break;
|
||||||
|
default: region_space_name = "Unknown"sv; break;
|
||||||
|
}
|
||||||
|
AML_DEBUG_PRINT_INDENT(indent);
|
||||||
|
AML_DEBUG_PRINT("OperationRegion(");
|
||||||
|
name.debug_print();
|
||||||
|
AML_DEBUG_PRINT(", {}, 0x{H}, 0x{H})", region_space_name, offset, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <BAN/HashMap.h>
|
||||||
|
#include <kernel/ACPI/AML/NamedObject.h>
|
||||||
|
#include <kernel/ACPI/AML/Names.h>
|
||||||
|
|
||||||
|
namespace Kernel::ACPI::AML
|
||||||
|
{
|
||||||
|
|
||||||
|
struct Scope : public AML::NamedObject
|
||||||
|
{
|
||||||
|
BAN::HashMap<NameSeg, BAN::RefPtr<NamedObject>> objects;
|
||||||
|
|
||||||
|
Scope(NameSeg name, Node::Type type = Node::Type::Scope) : NamedObject(type, name) {}
|
||||||
|
|
||||||
|
virtual bool is_scope() const override { return true; }
|
||||||
|
|
||||||
|
static ParseResult parse(ParseContext& context);
|
||||||
|
virtual void debug_print(int indent) const override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
ParseResult enter_context_and_parse_term_list(ParseContext& outer_context, const AML::NameString& name, BAN::ConstByteSpan aml_data);
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,51 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <kernel/ACPI/AML/Bytes.h>
|
||||||
|
#include <kernel/ACPI/AML/Node.h>
|
||||||
|
#include <kernel/ACPI/AML/ParseContext.h>
|
||||||
|
|
||||||
|
namespace Kernel::ACPI::AML
|
||||||
|
{
|
||||||
|
|
||||||
|
struct String : public AML::Node
|
||||||
|
{
|
||||||
|
BAN::String string;
|
||||||
|
|
||||||
|
String() : Node(Node::Type::String) {}
|
||||||
|
|
||||||
|
static ParseResult parse(ParseContext& context)
|
||||||
|
{
|
||||||
|
ASSERT(context.aml_data.size() >= 1);
|
||||||
|
ASSERT(static_cast<AML::Byte>(context.aml_data[0]) == AML::Byte::StringPrefix);
|
||||||
|
context.aml_data = context.aml_data.slice(1);
|
||||||
|
|
||||||
|
BAN::String string;
|
||||||
|
|
||||||
|
while (context.aml_data.size() > 0)
|
||||||
|
{
|
||||||
|
if (context.aml_data[0] == 0x00)
|
||||||
|
break;
|
||||||
|
MUST(string.push_back(static_cast<char>(context.aml_data[0])));
|
||||||
|
context.aml_data = context.aml_data.slice(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (context.aml_data.size() == 0)
|
||||||
|
return ParseResult::Failure;
|
||||||
|
if (context.aml_data[0] != 0x00)
|
||||||
|
return ParseResult::Failure;
|
||||||
|
context.aml_data = context.aml_data.slice(1);
|
||||||
|
|
||||||
|
auto string_node = MUST(BAN::RefPtr<String>::create());
|
||||||
|
string_node->string = BAN::move(string);
|
||||||
|
|
||||||
|
return ParseResult(string_node);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void debug_print(int indent) const override
|
||||||
|
{
|
||||||
|
AML_DEBUG_PRINT_INDENT(indent);
|
||||||
|
AML_DEBUG_PRINT("String \"{}\"", string);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -1,328 +0,0 @@
|
||||||
#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&);
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <BAN/Formatter.h>
|
||||||
|
#include <kernel/Debug.h>
|
||||||
|
|
||||||
|
// AML_DEBUG_LEVEL:
|
||||||
|
// 0: No debug output
|
||||||
|
// 1: Dump AML after parsing
|
||||||
|
// 2: Dump AML while parsing
|
||||||
|
#define AML_DEBUG_LEVEL 0
|
||||||
|
|
||||||
|
#define AML_TODO(...) \
|
||||||
|
do { \
|
||||||
|
BAN::Formatter::print(Debug::putchar, "\e[33mTODO: "); \
|
||||||
|
BAN::Formatter::print(Debug::putchar, __VA_ARGS__); \
|
||||||
|
BAN::Formatter::println(Debug::putchar, "\e[m"); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define AML_ERROR(...) \
|
||||||
|
do { \
|
||||||
|
BAN::Formatter::print(Debug::putchar, "\e[31mERROR: "); \
|
||||||
|
BAN::Formatter::print(Debug::putchar, __VA_ARGS__); \
|
||||||
|
BAN::Formatter::println(Debug::putchar, "\e[m"); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define AML_PRINT(...) BAN::Formatter::println(Debug::putchar, __VA_ARGS__)
|
||||||
|
|
||||||
|
#define AML_DEBUG_PRINT_INDENT(indent) \
|
||||||
|
do { \
|
||||||
|
for (int i = 0; i < (indent) * 2; i++) \
|
||||||
|
AML_DEBUG_PUTC(' '); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define AML_DEBUG_PUTC(c) Debug::putchar(c)
|
||||||
|
#define AML_DEBUG_PRINT(...) BAN::Formatter::print(Debug::putchar, __VA_ARGS__)
|
||||||
|
#define AML_DEBUG_PRINTLN(...) BAN::Formatter::println(Debug::putchar, __VA_ARGS__)
|
|
@ -35,7 +35,7 @@ namespace Kernel::ACPI
|
||||||
|
|
||||||
auto dsdt = s_instance->get_header("DSDT", 0);
|
auto dsdt = s_instance->get_header("DSDT", 0);
|
||||||
ASSERT(dsdt);
|
ASSERT(dsdt);
|
||||||
AMLParser::parse_table(*dsdt);
|
s_instance->m_namespace = AMLParser::parse_table(*dsdt);
|
||||||
|
|
||||||
#if ARCH(x86_64)
|
#if ARCH(x86_64)
|
||||||
lai_create_namespace();
|
lai_create_namespace();
|
||||||
|
|
|
@ -3,33 +3,34 @@
|
||||||
#include <kernel/ACPI/ACPI.h>
|
#include <kernel/ACPI/ACPI.h>
|
||||||
#include <kernel/ACPI/AML.h>
|
#include <kernel/ACPI/AML.h>
|
||||||
|
|
||||||
#include <kernel/ACPI/AML/TermObject.h>
|
|
||||||
|
|
||||||
namespace Kernel::ACPI::AML { size_t g_depth = 0; }
|
|
||||||
|
|
||||||
namespace Kernel::ACPI
|
namespace Kernel::ACPI
|
||||||
{
|
{
|
||||||
|
|
||||||
AMLParser::AMLParser() = default;
|
AMLParser::AMLParser() = default;
|
||||||
AMLParser::~AMLParser() = default;
|
AMLParser::~AMLParser() = default;
|
||||||
|
|
||||||
AMLParser AMLParser::parse_table(const SDTHeader& header)
|
BAN::RefPtr<AML::Namespace> AMLParser::parse_table(const SDTHeader& header)
|
||||||
{
|
{
|
||||||
dprintln("Parsing {}, {} bytes of AML", header, header.length - sizeof(header));
|
dprintln("Parsing {}, {} bytes of AML", header, header.length);
|
||||||
|
|
||||||
auto aml_raw = BAN::ConstByteSpan { reinterpret_cast<const uint8_t*>(&header), header.length };
|
auto aml_raw = BAN::ConstByteSpan { reinterpret_cast<const uint8_t*>(&header), header.length };
|
||||||
aml_raw = aml_raw.slice(sizeof(header));
|
aml_raw = aml_raw.slice(sizeof(header));
|
||||||
|
|
||||||
if (!AML::TermList::can_parse(aml_raw))
|
auto ns = AML::Namespace::parse(aml_raw);
|
||||||
dwarnln("Can not AML term_list");
|
if (!ns)
|
||||||
else
|
|
||||||
{
|
{
|
||||||
auto term_list = AML::TermList::parse(aml_raw);
|
dwarnln("Failed to parse ACPI namespace");
|
||||||
if (!term_list.has_value())
|
|
||||||
dwarnln("Failed to parse AML term_list");
|
|
||||||
}
|
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if AML_DEBUG_LEVEL >= 1
|
||||||
|
ns->debug_print(0);
|
||||||
|
AML_DEBUG_PRINTLN("");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
dprintln("Parsed ACPI namespace");
|
||||||
|
|
||||||
|
return ns;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,278 +0,0 @@
|
||||||
#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);
|
|
||||||
|
|
||||||
BAN::Vector<uint8_t> data;
|
|
||||||
MUST(data.resize(BAN::Math::max(buffer_size->value, buffer_span.size())));
|
|
||||||
for (size_t i = 0; i < buffer_span.size(); i++)
|
|
||||||
data[i] = buffer_span[i];
|
|
||||||
|
|
||||||
return Buffer { .buffer_size = buffer_size.release_value(), .data = BAN::move(data) };
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// ComputationalData
|
|
||||||
|
|
||||||
bool AML::ComputationalData::can_parse(BAN::ConstByteSpan span)
|
|
||||||
{
|
|
||||||
if (span.size() < 1)
|
|
||||||
return false;
|
|
||||||
if (static_cast<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; package_span.size() > 0 && i < count; i++) \
|
|
||||||
{ \
|
|
||||||
if (DataRefObject::can_parse(package_span)) \
|
|
||||||
{ \
|
|
||||||
AML_TRY_PARSE(element, DataRefObject, package_span); \
|
|
||||||
MUST(elements.push_back(PackageElement { \
|
|
||||||
MUST(BAN::UniqPtr<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 {}; \
|
|
||||||
} \
|
|
||||||
} \
|
|
||||||
\
|
|
||||||
while (elements.size() < count) \
|
|
||||||
MUST(elements.push_back(PackageElement { Uninitialized {} })); \
|
|
||||||
\
|
|
||||||
return NAME { .elements = BAN::move(elements) }; \
|
|
||||||
}
|
|
||||||
|
|
||||||
AML_GEN_PACKAGE(Package)
|
|
||||||
AML_GEN_PACKAGE(VarPackage)
|
|
||||||
#undef AML_GEN_PACKAGE
|
|
||||||
|
|
||||||
// DataObject
|
|
||||||
|
|
||||||
bool AML::DataObject::can_parse(BAN::ConstByteSpan span)
|
|
||||||
{
|
|
||||||
if (ComputationalData::can_parse(span))
|
|
||||||
return true;
|
|
||||||
if (Package::can_parse(span))
|
|
||||||
return true;
|
|
||||||
if (VarPackage::can_parse(span))
|
|
||||||
return true;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
BAN::Optional<AML::DataObject> 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,224 @@
|
||||||
|
#include <kernel/ACPI/AML/Field.h>
|
||||||
|
|
||||||
|
namespace Kernel::ACPI
|
||||||
|
{
|
||||||
|
|
||||||
|
template<typename Element>
|
||||||
|
struct ParseFieldElementContext
|
||||||
|
{
|
||||||
|
AML::FieldRules field_rules;
|
||||||
|
uint64_t field_bit_offset;
|
||||||
|
BAN::ConstByteSpan field_pkg;
|
||||||
|
BAN::HashMap<AML::NameSeg, BAN::RefPtr<Element>> elements;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename Element>
|
||||||
|
static bool parse_field_element(ParseFieldElementContext<Element>& context)
|
||||||
|
{
|
||||||
|
ASSERT(context.field_pkg.size() >= 1);
|
||||||
|
switch (context.field_pkg[0])
|
||||||
|
{
|
||||||
|
case 0x00:
|
||||||
|
{
|
||||||
|
context.field_pkg = context.field_pkg.slice(1);
|
||||||
|
|
||||||
|
auto reserved_length = AML::parse_pkg_length(context.field_pkg);
|
||||||
|
if (!reserved_length.has_value())
|
||||||
|
{
|
||||||
|
AML_ERROR("Invalid FieldElement length for reserved field");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
AML::trim_pkg_length(context.field_pkg);
|
||||||
|
|
||||||
|
context.field_bit_offset += reserved_length.value();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
case 0x01:
|
||||||
|
case 0x02:
|
||||||
|
case 0x03:
|
||||||
|
AML_TODO("Field element {2H}", context.field_pkg[0]);
|
||||||
|
return false;
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
auto element_name = AML::NameSeg::parse(context.field_pkg);
|
||||||
|
if (!element_name.has_value())
|
||||||
|
{
|
||||||
|
AML_ERROR("Invalid FieldElement name for named field");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto element_length = AML::parse_pkg_length(context.field_pkg);
|
||||||
|
if (!element_length.has_value())
|
||||||
|
{
|
||||||
|
AML_ERROR("Invalid FieldElement length for named field");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
AML::trim_pkg_length(context.field_pkg);
|
||||||
|
|
||||||
|
if (context.elements.contains(element_name.value()))
|
||||||
|
{
|
||||||
|
AML_ERROR("Field element already exists");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
MUST(context.elements.emplace(
|
||||||
|
element_name.value(),
|
||||||
|
MUST(BAN::RefPtr<Element>::create(
|
||||||
|
element_name.value(),
|
||||||
|
context.field_bit_offset,
|
||||||
|
element_length.value(),
|
||||||
|
context.field_rules
|
||||||
|
))
|
||||||
|
));
|
||||||
|
context.field_bit_offset += element_length.value();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AML::ParseResult AML::Field::parse(ParseContext& context)
|
||||||
|
{
|
||||||
|
ASSERT(context.aml_data.size() >= 2);
|
||||||
|
ASSERT(static_cast<AML::Byte>(context.aml_data[0]) == AML::Byte::ExtOpPrefix);
|
||||||
|
ASSERT(static_cast<AML::ExtOp>(context.aml_data[1]) == AML::ExtOp::FieldOp);
|
||||||
|
context.aml_data = context.aml_data.slice(2);
|
||||||
|
|
||||||
|
auto opt_field_pkg = AML::parse_pkg(context.aml_data);
|
||||||
|
if (!opt_field_pkg.has_value())
|
||||||
|
return ParseResult::Failure;
|
||||||
|
auto field_pkg = opt_field_pkg.release_value();
|
||||||
|
|
||||||
|
auto name_string = NameString::parse(field_pkg);
|
||||||
|
if (!name_string.has_value())
|
||||||
|
return ParseResult::Failure;
|
||||||
|
|
||||||
|
auto op_region = context.root_namespace->find_object(context.scope.span(), name_string.value());
|
||||||
|
if (!op_region || op_region->type != AML::Node::Type::OpRegion)
|
||||||
|
{
|
||||||
|
AML_ERROR("Field RegionName does not name a valid OpRegion");
|
||||||
|
return ParseResult::Failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (field_pkg.size() < 1)
|
||||||
|
return ParseResult::Failure;
|
||||||
|
auto field_flags = field_pkg[0];
|
||||||
|
field_pkg = field_pkg.slice(1);
|
||||||
|
|
||||||
|
ParseFieldElementContext<FieldElement> field_context;
|
||||||
|
field_context.field_rules.access_type = static_cast<FieldRules::AccessType>(field_flags & 0x0F);
|
||||||
|
field_context.field_rules.lock_rule = static_cast<FieldRules::LockRule>((field_flags >> 4) & 0x01);
|
||||||
|
field_context.field_rules.update_rule = static_cast<FieldRules::UpdateRule>((field_flags >> 5) & 0x03);
|
||||||
|
field_context.field_bit_offset = 0;
|
||||||
|
field_context.field_pkg = field_pkg;
|
||||||
|
while (field_context.field_pkg.size() > 0)
|
||||||
|
if (!parse_field_element(field_context))
|
||||||
|
return ParseResult::Failure;
|
||||||
|
|
||||||
|
for (auto& [_, element] : field_context.elements)
|
||||||
|
{
|
||||||
|
element->op_region = static_cast<OpRegion*>(op_region.ptr());
|
||||||
|
|
||||||
|
NameString element_name;
|
||||||
|
MUST(element_name.path.push_back(element->name));
|
||||||
|
if (!context.root_namespace->add_named_object(context.scope.span(), element_name, element))
|
||||||
|
return ParseResult::Failure;
|
||||||
|
|
||||||
|
#if AML_DEBUG_LEVEL >= 2
|
||||||
|
element->debug_print(0);
|
||||||
|
AML_DEBUG_PRINTLN("");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
return ParseResult::Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AML::FieldElement::debug_print(int indent) const
|
||||||
|
{
|
||||||
|
AML_DEBUG_PRINT_INDENT(indent);
|
||||||
|
AML_DEBUG_PRINT("FieldElement ");
|
||||||
|
name.debug_print();
|
||||||
|
AML_DEBUG_PRINT("({}, offset {}, OpRegion ", bit_count, bit_offset);
|
||||||
|
op_region->name.debug_print();
|
||||||
|
AML_DEBUG_PRINT(")");
|
||||||
|
}
|
||||||
|
|
||||||
|
AML::ParseResult AML::IndexField::parse(ParseContext& context)
|
||||||
|
{
|
||||||
|
ASSERT(context.aml_data.size() >= 2);
|
||||||
|
ASSERT(static_cast<AML::Byte>(context.aml_data[0]) == AML::Byte::ExtOpPrefix);
|
||||||
|
ASSERT(static_cast<AML::ExtOp>(context.aml_data[1]) == AML::ExtOp::IndexFieldOp);
|
||||||
|
context.aml_data = context.aml_data.slice(2);
|
||||||
|
|
||||||
|
auto opt_field_pkg = AML::parse_pkg(context.aml_data);
|
||||||
|
if (!opt_field_pkg.has_value())
|
||||||
|
return ParseResult::Failure;
|
||||||
|
auto field_pkg = opt_field_pkg.release_value();
|
||||||
|
|
||||||
|
auto index_field_element_name = NameString::parse(field_pkg);
|
||||||
|
if (!index_field_element_name.has_value())
|
||||||
|
return ParseResult::Failure;
|
||||||
|
auto index_field_element = context.root_namespace->find_object(context.scope.span(), index_field_element_name.value());
|
||||||
|
if (!index_field_element || index_field_element->type != AML::Node::Type::FieldElement)
|
||||||
|
{
|
||||||
|
AML_ERROR("IndexField IndexName does not name a valid FieldElement");
|
||||||
|
return ParseResult::Failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto data_field_element_name = NameString::parse(field_pkg);
|
||||||
|
if (!data_field_element_name.has_value())
|
||||||
|
return ParseResult::Failure;
|
||||||
|
auto data_field_element = context.root_namespace->find_object(context.scope.span(), data_field_element_name.value());
|
||||||
|
if (!data_field_element || data_field_element->type != AML::Node::Type::FieldElement)
|
||||||
|
{
|
||||||
|
AML_ERROR("IndexField DataName does not name a valid FieldElement");
|
||||||
|
return ParseResult::Failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (field_pkg.size() < 1)
|
||||||
|
return ParseResult::Failure;
|
||||||
|
auto field_flags = field_pkg[0];
|
||||||
|
field_pkg = field_pkg.slice(1);
|
||||||
|
|
||||||
|
ParseFieldElementContext<IndexFieldElement> field_context;
|
||||||
|
field_context.field_rules.access_type = static_cast<FieldRules::AccessType>(field_flags & 0x0F);
|
||||||
|
field_context.field_rules.lock_rule = static_cast<FieldRules::LockRule>((field_flags >> 4) & 0x01);
|
||||||
|
field_context.field_rules.update_rule = static_cast<FieldRules::UpdateRule>((field_flags >> 5) & 0x03);
|
||||||
|
field_context.field_bit_offset = 0;
|
||||||
|
field_context.field_pkg = field_pkg;
|
||||||
|
while (field_context.field_pkg.size() > 0)
|
||||||
|
if (!parse_field_element(field_context))
|
||||||
|
return ParseResult::Failure;
|
||||||
|
|
||||||
|
for (auto& [_, element] : field_context.elements)
|
||||||
|
{
|
||||||
|
element->index_element = static_cast<FieldElement*>(index_field_element.ptr());
|
||||||
|
element->data_element = static_cast<FieldElement*>(data_field_element.ptr());
|
||||||
|
|
||||||
|
NameString element_name;
|
||||||
|
MUST(element_name.path.push_back(element->name));
|
||||||
|
if (!context.root_namespace->add_named_object(context.scope.span(), element_name, element))
|
||||||
|
return ParseResult::Failure;
|
||||||
|
|
||||||
|
#if AML_DEBUG_LEVEL >= 2
|
||||||
|
element->debug_print(0);
|
||||||
|
AML_DEBUG_PRINTLN("");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
return AML::ParseResult::Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AML::IndexFieldElement::debug_print(int indent) const
|
||||||
|
{
|
||||||
|
AML_DEBUG_PRINT_INDENT(indent);
|
||||||
|
AML_DEBUG_PRINT("IndexFieldElement ");
|
||||||
|
name.debug_print();
|
||||||
|
AML_DEBUG_PRINT("({}, offset {}, IndexName ", bit_count, bit_offset);
|
||||||
|
index_element->name.debug_print();
|
||||||
|
AML_DEBUG_PRINT(", DataName ");
|
||||||
|
data_element->name.debug_print();
|
||||||
|
AML_DEBUG_PRINT(")");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,99 +0,0 @@
|
||||||
#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 {};
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,162 +0,0 @@
|
||||||
#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())) };
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
#include <kernel/ACPI/AML/NamedObject.h>
|
||||||
|
#include <kernel/ACPI/AML/ParseContext.h>
|
||||||
|
|
||||||
|
namespace Kernel::ACPI
|
||||||
|
{
|
||||||
|
|
||||||
|
AML::ParseResult AML::Name::parse(ParseContext& context)
|
||||||
|
{
|
||||||
|
ASSERT(context.aml_data.size() >= 1);
|
||||||
|
ASSERT(static_cast<Byte>(context.aml_data[0]) == Byte::NameOp);
|
||||||
|
context.aml_data = context.aml_data.slice(1);
|
||||||
|
|
||||||
|
auto name_string = AML::NameString::parse(context.aml_data);
|
||||||
|
if (!name_string.has_value())
|
||||||
|
return ParseResult::Failure;
|
||||||
|
|
||||||
|
auto object = AML::parse_object(context);
|
||||||
|
if (!object.success())
|
||||||
|
return ParseResult::Failure;
|
||||||
|
|
||||||
|
auto name = MUST(BAN::RefPtr<Name>::create(name_string.value().path.back(), object.node()));
|
||||||
|
if (!context.root_namespace->add_named_object(context.scope.span(), name_string.value(), name))
|
||||||
|
return ParseResult::Failure;
|
||||||
|
|
||||||
|
#if AML_DEBUG_LEVEL >= 2
|
||||||
|
name->debug_print(0);
|
||||||
|
AML_DEBUG_PRINTLN("");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return ParseResult::Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AML::Name::debug_print(int indent) const
|
||||||
|
{
|
||||||
|
AML_DEBUG_PRINT_INDENT(indent);
|
||||||
|
AML_DEBUG_PRINT("Name ");
|
||||||
|
name.debug_print();
|
||||||
|
AML_DEBUG_PRINTLN(" {");
|
||||||
|
object->debug_print(indent + 1);
|
||||||
|
AML_DEBUG_PRINTLN("");
|
||||||
|
AML_DEBUG_PRINT_INDENT(indent);
|
||||||
|
AML_DEBUG_PRINT("}");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,123 @@
|
||||||
|
#include <kernel/ACPI/AML/Namespace.h>
|
||||||
|
#include <kernel/ACPI/AML/ParseContext.h>
|
||||||
|
#include <kernel/ACPI/AML/Region.h>
|
||||||
|
|
||||||
|
namespace Kernel::ACPI
|
||||||
|
{
|
||||||
|
|
||||||
|
BAN::Optional<BAN::Vector<AML::NameSeg>> AML::Namespace::resolve_path(BAN::Span<const AML::NameSeg> parsing_scope, const AML::NameString& relative_path)
|
||||||
|
{
|
||||||
|
BAN::Vector<NameSeg> canonical_path;
|
||||||
|
|
||||||
|
if (!relative_path.prefix.empty())
|
||||||
|
{
|
||||||
|
if (relative_path.prefix[0] == '\\')
|
||||||
|
;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (parsing_scope.size() < relative_path.prefix.size())
|
||||||
|
{
|
||||||
|
AML_ERROR("Trying to resolve parent of root object");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
for (size_t i = 0; i < parsing_scope.size() - relative_path.prefix.size(); i++)
|
||||||
|
MUST(canonical_path.push_back(parsing_scope[i]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (auto seg : parsing_scope)
|
||||||
|
MUST(canonical_path.push_back(seg));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto& seg : relative_path.path)
|
||||||
|
MUST(canonical_path.push_back(seg));
|
||||||
|
|
||||||
|
return canonical_path;
|
||||||
|
}
|
||||||
|
|
||||||
|
BAN::RefPtr<AML::NamedObject> AML::Namespace::find_object(BAN::Span<const AML::NameSeg> parsing_scope, const AML::NameString& relative_path)
|
||||||
|
{
|
||||||
|
auto canonical_path = resolve_path(parsing_scope, relative_path);
|
||||||
|
if (!canonical_path.has_value())
|
||||||
|
return nullptr;
|
||||||
|
if (canonical_path->empty())
|
||||||
|
return this;
|
||||||
|
|
||||||
|
BAN::RefPtr<NamedObject> parent_object = this;
|
||||||
|
|
||||||
|
for (const auto& seg : canonical_path.value())
|
||||||
|
{
|
||||||
|
if (!parent_object->is_scope())
|
||||||
|
{
|
||||||
|
AML_ERROR("Parent object is not a scope");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto* parent_scope = static_cast<Scope*>(parent_object.ptr());
|
||||||
|
|
||||||
|
auto it = parent_scope->objects.find(seg);
|
||||||
|
if (it == parent_scope->objects.end())
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
parent_object = it->value;
|
||||||
|
ASSERT(parent_object);
|
||||||
|
}
|
||||||
|
|
||||||
|
return parent_object;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AML::Namespace::add_named_object(BAN::Span<const NameSeg> parsing_scope, const AML::NameString& object_path, BAN::RefPtr<NamedObject> object)
|
||||||
|
{
|
||||||
|
ASSERT(!object_path.path.empty());
|
||||||
|
ASSERT(object_path.path.back() == object->name);
|
||||||
|
|
||||||
|
auto parent_path = object_path;
|
||||||
|
parent_path.path.pop_back();
|
||||||
|
|
||||||
|
auto parent_object = find_object(parsing_scope, parent_path);
|
||||||
|
if (!parent_object)
|
||||||
|
{
|
||||||
|
AML_ERROR("Parent object not found");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!parent_object->is_scope())
|
||||||
|
{
|
||||||
|
AML_ERROR("Parent object is not a scope");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto* parent_scope = static_cast<Scope*>(parent_object.ptr());
|
||||||
|
if (parent_scope->objects.contains(object->name))
|
||||||
|
{
|
||||||
|
AML_ERROR("Object already exists");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
MUST(parent_scope->objects.insert(object->name, object));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
BAN::RefPtr<AML::Namespace> AML::Namespace::parse(BAN::ConstByteSpan aml_data)
|
||||||
|
{
|
||||||
|
auto result = MUST(BAN::RefPtr<Namespace>::create());
|
||||||
|
|
||||||
|
AML::ParseContext context;
|
||||||
|
context.aml_data = aml_data;
|
||||||
|
context.root_namespace = result.ptr();
|
||||||
|
|
||||||
|
while (context.aml_data.size() > 0)
|
||||||
|
{
|
||||||
|
auto result = AML::parse_object(context);
|
||||||
|
if (!result.success())
|
||||||
|
{
|
||||||
|
AML_ERROR("Failed to parse object");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,102 @@
|
||||||
|
#include <kernel/ACPI/AML/Buffer.h>
|
||||||
|
#include <kernel/ACPI/AML/Bytes.h>
|
||||||
|
#include <kernel/ACPI/AML/Device.h>
|
||||||
|
#include <kernel/ACPI/AML/Field.h>
|
||||||
|
#include <kernel/ACPI/AML/Integer.h>
|
||||||
|
#include <kernel/ACPI/AML/Method.h>
|
||||||
|
#include <kernel/ACPI/AML/Mutex.h>
|
||||||
|
#include <kernel/ACPI/AML/Names.h>
|
||||||
|
#include <kernel/ACPI/AML/Node.h>
|
||||||
|
#include <kernel/ACPI/AML/Package.h>
|
||||||
|
#include <kernel/ACPI/AML/ParseContext.h>
|
||||||
|
#include <kernel/ACPI/AML/Processor.h>
|
||||||
|
#include <kernel/ACPI/AML/Region.h>
|
||||||
|
#include <kernel/ACPI/AML/String.h>
|
||||||
|
#include <kernel/ACPI/AML/Utils.h>
|
||||||
|
|
||||||
|
namespace Kernel::ACPI
|
||||||
|
{
|
||||||
|
|
||||||
|
AML::ParseResult AML::ParseResult::Failure = AML::ParseResult(AML::ParseResult::Result::Failure);
|
||||||
|
AML::ParseResult AML::ParseResult::Success = AML::ParseResult(AML::ParseResult::Result::Success);
|
||||||
|
|
||||||
|
AML::ParseResult AML::parse_object(AML::ParseContext& context)
|
||||||
|
{
|
||||||
|
if (context.aml_data.size() < 1)
|
||||||
|
return ParseResult::Failure;
|
||||||
|
|
||||||
|
if (static_cast<AML::Byte>(context.aml_data[0]) == AML::Byte::ExtOpPrefix)
|
||||||
|
{
|
||||||
|
if (context.aml_data.size() < 2)
|
||||||
|
return ParseResult::Failure;
|
||||||
|
|
||||||
|
switch (static_cast<AML::ExtOp>(context.aml_data[1]))
|
||||||
|
{
|
||||||
|
case AML::ExtOp::FieldOp:
|
||||||
|
return AML::Field::parse(context);
|
||||||
|
case AML::ExtOp::IndexFieldOp:
|
||||||
|
return AML::IndexField::parse(context);
|
||||||
|
case AML::ExtOp::OpRegionOp:
|
||||||
|
return AML::OpRegion::parse(context);
|
||||||
|
case AML::ExtOp::DeviceOp:
|
||||||
|
return AML::Device::parse(context);
|
||||||
|
case AML::ExtOp::MutexOp:
|
||||||
|
return AML::Mutex::parse(context);
|
||||||
|
case AML::ExtOp::ProcessorOp:
|
||||||
|
return AML::Processor::parse(context);
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
AML_TODO("{2H} {2H}", context.aml_data[0], context.aml_data[1]);
|
||||||
|
return ParseResult::Failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (static_cast<AML::Byte>(context.aml_data[0]))
|
||||||
|
{
|
||||||
|
case AML::Byte::ZeroOp:
|
||||||
|
case AML::Byte::OneOp:
|
||||||
|
case AML::Byte::OnesOp:
|
||||||
|
case AML::Byte::BytePrefix:
|
||||||
|
case AML::Byte::WordPrefix:
|
||||||
|
case AML::Byte::DWordPrefix:
|
||||||
|
case AML::Byte::QWordPrefix:
|
||||||
|
return AML::Integer::parse(context.aml_data);
|
||||||
|
case AML::Byte::StringPrefix:
|
||||||
|
return AML::String::parse(context);
|
||||||
|
case AML::Byte::NameOp:
|
||||||
|
return AML::Name::parse(context);
|
||||||
|
case AML::Byte::PackageOp:
|
||||||
|
return AML::Package::parse(context);
|
||||||
|
case AML::Byte::MethodOp:
|
||||||
|
return AML::Method::parse(context);
|
||||||
|
case AML::Byte::BufferOp:
|
||||||
|
return AML::Buffer::parse(context);
|
||||||
|
case AML::Byte::ScopeOp:
|
||||||
|
return AML::Scope::parse(context);
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (static_cast<AML::Byte>(context.aml_data[0]) == AML::Byte::RootChar
|
||||||
|
|| static_cast<AML::Byte>(context.aml_data[0]) == AML::Byte::ParentPrefixChar
|
||||||
|
|| static_cast<AML::Byte>(context.aml_data[0]) == AML::Byte::NullName
|
||||||
|
|| is_lead_name_char(context.aml_data[0]))
|
||||||
|
{
|
||||||
|
auto name_string = AML::NameString::parse(context.aml_data);
|
||||||
|
if (!name_string.has_value())
|
||||||
|
return ParseResult::Failure;
|
||||||
|
auto aml_object = context.root_namespace->find_object(context.scope.span(), name_string.value());
|
||||||
|
if (!aml_object)
|
||||||
|
{
|
||||||
|
AML_TODO("NameString not found in namespace");
|
||||||
|
return ParseResult::Failure;
|
||||||
|
}
|
||||||
|
return ParseResult(aml_object);
|
||||||
|
}
|
||||||
|
|
||||||
|
AML_TODO("{2H}", context.aml_data[0]);
|
||||||
|
return ParseResult::Failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,77 @@
|
||||||
|
#include <kernel/ACPI/AML/Device.h>
|
||||||
|
#include <kernel/ACPI/AML/ParseContext.h>
|
||||||
|
#include <kernel/ACPI/AML/Pkg.h>
|
||||||
|
#include <kernel/ACPI/AML/Scope.h>
|
||||||
|
|
||||||
|
namespace Kernel::ACPI
|
||||||
|
{
|
||||||
|
|
||||||
|
AML::ParseResult AML::Scope::parse(ParseContext& context)
|
||||||
|
{
|
||||||
|
ASSERT(context.aml_data.size() >= 1);
|
||||||
|
ASSERT(static_cast<AML::Byte>(context.aml_data[0]) == AML::Byte::ScopeOp);
|
||||||
|
context.aml_data = context.aml_data.slice(1);
|
||||||
|
|
||||||
|
auto scope_pkg = AML::parse_pkg(context.aml_data);
|
||||||
|
if (!scope_pkg.has_value())
|
||||||
|
return ParseResult::Failure;
|
||||||
|
|
||||||
|
auto name_string = AML::NameString::parse(scope_pkg.value());
|
||||||
|
if (!name_string.has_value())
|
||||||
|
return ParseResult::Failure;
|
||||||
|
|
||||||
|
BAN::RefPtr<Scope> scope;
|
||||||
|
if (auto named_object = context.root_namespace->find_object(context.scope.span(), name_string.value()))
|
||||||
|
{
|
||||||
|
if (!named_object->is_scope())
|
||||||
|
{
|
||||||
|
AML_ERROR("Scope name already exists and is not a scope");
|
||||||
|
return ParseResult::Failure;
|
||||||
|
}
|
||||||
|
scope = static_cast<Scope*>(named_object.ptr());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
scope = MUST(BAN::RefPtr<Scope>::create(name_string->path.back()));
|
||||||
|
if (!context.root_namespace->add_named_object(context.scope.span(), name_string.value(), scope))
|
||||||
|
return ParseResult::Failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
return scope->enter_context_and_parse_term_list(context, name_string.value(), scope_pkg.value());
|
||||||
|
}
|
||||||
|
|
||||||
|
AML::ParseResult AML::Scope::enter_context_and_parse_term_list(ParseContext& outer_context, const AML::NameString& name_string, BAN::ConstByteSpan aml_data)
|
||||||
|
{
|
||||||
|
auto scope = outer_context.root_namespace->resolve_path(outer_context.scope.span(), name_string);
|
||||||
|
if (!scope.has_value())
|
||||||
|
return ParseResult::Failure;
|
||||||
|
|
||||||
|
ParseContext scope_context = outer_context;
|
||||||
|
scope_context.scope = scope.release_value();
|
||||||
|
scope_context.aml_data = aml_data;
|
||||||
|
while (scope_context.aml_data.size() > 0)
|
||||||
|
{
|
||||||
|
auto object_result = AML::parse_object(scope_context);
|
||||||
|
if (!object_result.success())
|
||||||
|
return ParseResult::Failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ParseResult::Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AML::Scope::debug_print(int indent) const
|
||||||
|
{
|
||||||
|
AML_DEBUG_PRINT_INDENT(indent);
|
||||||
|
AML_DEBUG_PRINT("Scope ");
|
||||||
|
name.debug_print();
|
||||||
|
AML_DEBUG_PRINTLN(" {");
|
||||||
|
for (const auto& [name, object] : objects)
|
||||||
|
{
|
||||||
|
object->debug_print(indent + 1);
|
||||||
|
AML_DEBUG_PRINTLN("");
|
||||||
|
}
|
||||||
|
AML_DEBUG_PRINT_INDENT(indent);
|
||||||
|
AML_DEBUG_PRINT("}");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue