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:
114
kernel/include/kernel/ACPI/AML/Region.h
Normal file
114
kernel/include/kernel/ACPI/AML/Region.h
Normal file
@@ -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);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user