banan-os/kernel/include/kernel/ACPI/AML/Region.h

117 lines
3.8 KiB
C++

#pragma once
#include <kernel/ACPI/AML/Integer.h>
#include <kernel/ACPI/AML/NamedObject.h>
#include <kernel/ACPI/AML/Namespace.h>
#include <kernel/ACPI/AML/ParseContext.h>
namespace Kernel::ACPI::AML
{
struct OpRegion final : public AML::NamedObject
{
using RegionSpace = GAS::AddressSpaceID;
RegionSpace region_space;
uint64_t region_offset;
uint64_t region_length;
Kernel::Mutex mutex;
OpRegion(NameSeg name, RegionSpace region_space, uint64_t region_offset, uint64_t region_length)
: NamedObject(Node::Type::OpRegion, name)
, region_space(region_space)
, region_offset(region_offset)
, region_length(region_length)
{}
BAN::RefPtr<AML::Node> convert(uint8_t) override { return {}; }
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_node = offset_result.node()
? offset_result.node()->convert(AML::Node::ConvInteger)
: BAN::RefPtr<AML::Node>();
if (!offset_node)
{
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_node = length_result.node()
? length_result.node()->convert(AML::Node::ConvInteger)
: BAN::RefPtr<AML::Node>();
if (!length_node)
{
AML_ERROR("OpRegion length must be an integer");
return ParseResult::Failure;
}
const auto offset = static_cast<AML::Integer*>(offset_node.ptr())->value;
const auto length = static_cast<AML::Integer*>(length_node.ptr())->value;
auto op_region = MUST(BAN::RefPtr<OpRegion>::create(
name->path.back(),
region_space,
offset,
length
));
if (!Namespace::root_namespace()->add_named_object(context, name.value(), op_region))
return ParseResult::Success;
#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 (region_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::PlatformCommunicationChannel: region_space_name = "PlatformCommunicationChannel"_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, region_offset, region_length);
}
};
}