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:
2024-04-09 01:16:07 +03:00
parent 090a294017
commit b16e65168f
38 changed files with 1891 additions and 2412 deletions

View File

@@ -35,7 +35,7 @@ namespace Kernel::ACPI
auto dsdt = s_instance->get_header("DSDT", 0);
ASSERT(dsdt);
AMLParser::parse_table(*dsdt);
s_instance->m_namespace = AMLParser::parse_table(*dsdt);
#if ARCH(x86_64)
lai_create_namespace();

View File

@@ -3,33 +3,34 @@
#include <kernel/ACPI/ACPI.h>
#include <kernel/ACPI/AML.h>
#include <kernel/ACPI/AML/TermObject.h>
namespace Kernel::ACPI::AML { size_t g_depth = 0; }
namespace Kernel::ACPI
{
AMLParser::AMLParser() = default;
AMLParser::~AMLParser() = default;
AMLParser AMLParser::parse_table(const SDTHeader& header)
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 };
aml_raw = aml_raw.slice(sizeof(header));
if (!AML::TermList::can_parse(aml_raw))
dwarnln("Can not AML term_list");
else
auto ns = AML::Namespace::parse(aml_raw);
if (!ns)
{
auto term_list = AML::TermList::parse(aml_raw);
if (!term_list.has_value())
dwarnln("Failed to parse AML term_list");
dwarnln("Failed to parse ACPI namespace");
return {};
}
return {};
#if AML_DEBUG_LEVEL >= 1
ns->debug_print(0);
AML_DEBUG_PRINTLN("");
#endif
dprintln("Parsed ACPI namespace");
return ns;
}
}

View File

@@ -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();
}
}

View File

@@ -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(")");
}
}

View File

@@ -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 {};
}
}

View File

@@ -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())) };
}
}

View File

@@ -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("}");
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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