Kernel: Replace the old AML interpreter by a new, better one

The old AML interpreter was trash and did not follow value/reference
semantics at all. It was also super slow, one of my machines taking over
7 seconds to parse ACPI namespace and call _INI and _STA.
This commit is contained in:
2024-12-12 07:03:09 +02:00
parent 463bb72d24
commit 869f4011a1
55 changed files with 5230 additions and 5913 deletions

View File

@@ -1,7 +1,6 @@
#pragma once
#include <BAN/Vector.h>
#include <kernel/ACPI/AML/Method.h>
#include <kernel/ACPI/AML/Namespace.h>
#include <kernel/ACPI/Headers.h>
#include <kernel/Memory/Types.h>
@@ -29,13 +28,8 @@ namespace Kernel::ACPI
// 2: SAPIC
BAN::ErrorOr<void> enter_acpi_mode(uint8_t mode);
// This function will power off the system
// This function will return only if there was an error
void poweroff();
// This function will reset the system
// This function will return only if there was an error
void reset();
BAN::ErrorOr<void> poweroff();
BAN::ErrorOr<void> reset();
void handle_irq() override;
@@ -45,9 +39,11 @@ namespace Kernel::ACPI
FADT& fadt() { return *m_fadt; }
bool prepare_sleep(uint8_t sleep_state);
BAN::ErrorOr<void> prepare_sleep(uint8_t sleep_state);
void acpi_event_task();
BAN::ErrorOr<void> load_aml_tables(BAN::StringView name, bool all);
private:
paddr_t m_header_table_paddr = 0;
vaddr_t m_header_table_vaddr = 0;
@@ -65,10 +61,12 @@ namespace Kernel::ACPI
FADT* m_fadt { nullptr };
ThreadBlocker m_event_thread_blocker;
BAN::Array<BAN::RefPtr<AML::Method>, 0xFF> m_gpe_methods;
AML::Scope m_gpe_scope;
BAN::Array<AML::Reference*, 0xFF> m_gpe_methods { nullptr };
bool m_hardware_reduced { false };
BAN::RefPtr<AML::Namespace> m_namespace;
AML::Namespace* m_namespace { nullptr };
};
}

View File

@@ -1,11 +0,0 @@
#pragma once
#include <kernel/ACPI/Headers.h>
#include <kernel/ACPI/AML/Namespace.h>
namespace Kernel::ACPI::AML
{
BAN::RefPtr<AML::Namespace> initialize_namespace();
}

View File

@@ -1,48 +0,0 @@
#pragma once
#include <kernel/ACPI/AML/NamedObject.h>
#include <kernel/ACPI/AML/Names.h>
#include <kernel/ACPI/AML/ParseContext.h>
namespace Kernel::ACPI::AML
{
struct Alias
{
static ParseResult parse(ParseContext& context)
{
ASSERT(context.aml_data.size() >= 1);
ASSERT(static_cast<Byte>(context.aml_data[0]) == Byte::AliasOp);
context.aml_data = context.aml_data.slice(1);
auto source_string = AML::NameString::parse(context.aml_data);
if (!source_string.has_value())
return ParseResult::Failure;
auto source_object = AML::Namespace::root_namespace()->find_object(context.scope, source_string.value(), AML::Namespace::FindMode::Normal);
auto alias_string = AML::NameString::parse(context.aml_data);
if (!alias_string.has_value())
return ParseResult::Failure;
if (!source_object)
{
AML_PRINT("Alias target could not be found");
return ParseResult::Success;
}
if (!Namespace::root_namespace()->add_named_object(context, alias_string.value(), source_object))
return ParseResult::Success;
#if AML_DEBUG_LEVEL >= 2
AML_DEBUG_PRINT("Alias \"");
alias_string->debug_print();
AML_DEBUG_PRINT("\" => ");
source_object->debug_print(0);
AML_DEBUG_PRINTLN("");
#endif
return ParseResult::Success;
}
};
}

View File

@@ -1,312 +0,0 @@
#pragma once
#include <kernel/ACPI/AML/Bytes.h>
#include <kernel/ACPI/AML/Integer.h>
#include <kernel/ACPI/AML/Node.h>
#include <kernel/ACPI/AML/ParseContext.h>
#include <kernel/ACPI/AML/Pkg.h>
#include <kernel/ACPI/AML/String.h>
namespace Kernel::ACPI::AML
{
struct Buffer final : public AML::Node
{
BAN::Vector<uint8_t> buffer;
Buffer()
: AML::Node(Node::Type::Buffer)
{}
BAN::Optional<bool> logical_compare(BAN::RefPtr<AML::Node> node, AML::Byte binaryop)
{
auto rhs_node = node ? node->convert(AML::Node::ConvBuffer) : BAN::RefPtr<AML::Node>();
if (!rhs_node)
{
AML_ERROR("Buffer logical compare RHS cannot be converted to buffer");
return {};
}
(void)binaryop;
AML_TODO("Logical compare buffer");
return {};
}
BAN::RefPtr<AML::Node> convert(uint8_t mask) override
{
if (mask & AML::Node::ConvBuffer)
return this;
if (mask & AML::Node::ConvInteger)
return as_integer();
if (mask & AML::Node::ConvString)
{
AML_TODO("Convert BufferField to String");
return {};
}
return {};
}
BAN::RefPtr<AML::Node> store(BAN::RefPtr<AML::Node> node) override
{
ASSERT(node);
auto conv_node = node->convert(AML::Node::ConvBuffer);
if (!conv_node)
{
AML_ERROR("Buffer store could not convert to buffer");
return {};
}
auto& conv_buffer = static_cast<AML::Buffer*>(conv_node.ptr())->buffer;
MUST(buffer.resize(conv_buffer.size()));
for (size_t i = 0; i < buffer.size(); i++)
buffer[i] = conv_buffer[i];
return this;
}
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_result = AML::parse_object(buffer_context);
if (!buffer_size_result.success())
return ParseResult::Failure;
auto buffer_size_node = buffer_size_result.node() ? buffer_size_result.node()->convert(AML::Node::ConvInteger) : BAN::RefPtr<AML::Node>();
if (!buffer_size_node)
{
AML_ERROR("Buffer size is not an integer");
return ParseResult::Failure;
}
const uint32_t actual_buffer_size = BAN::Math::max<uint32_t>(
static_cast<AML::Integer*>(buffer_size_node.ptr())->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());
}
private:
BAN::RefPtr<AML::Integer> as_integer()
{
uint64_t value = 0;
for (size_t i = 0; i < BAN::Math::min<size_t>(buffer.size(), 8); i++)
value |= static_cast<uint64_t>(buffer[i]) << (8 * i);
return MUST(BAN::RefPtr<Integer>::create(value));
}
};
struct BufferField final : AML::NamedObject
{
BAN::RefPtr<AML::Node> buffer;
size_t field_bit_offset;
size_t field_bit_size;
template<typename T> requires BAN::is_same_v<T, AML::Buffer> || BAN::is_same_v<T, AML::String>
BufferField(AML::NameSeg name, BAN::RefPtr<T> buffer, size_t field_bit_offset, size_t field_bit_size)
: AML::NamedObject(Node::Type::BufferField, name)
, buffer(buffer)
, field_bit_offset(field_bit_offset)
, field_bit_size(field_bit_size)
{}
BAN::RefPtr<AML::Node> convert(uint8_t mask) override
{
if (mask & AML::Node::ConvBufferField)
return this;
if (mask & AML::Node::ConvInteger)
return as_integer();
if (mask & AML::Node::ConvBuffer)
{
AML_TODO("Convert BufferField to Buffer");
return {};
}
if (mask & AML::Node::ConvString)
{
AML_TODO("Convert BufferField to String");
return {};
}
return {};
}
BAN::RefPtr<AML::Node> store(BAN::RefPtr<AML::Node> node) override
{
ASSERT(buffer);
ASSERT(buffer->type == AML::Node::Type::Buffer || buffer->type == AML::Node::Type::String);
auto& buffer = (this->buffer->type == AML::Node::Type::Buffer)
? static_cast<AML::Buffer*>(this->buffer.ptr())->buffer
: static_cast<AML::String*>(this->buffer.ptr())->string;
ASSERT(field_bit_offset + field_bit_size <= buffer.size() * 8);
auto value_node = node ? node->convert(AML::Node::ConvInteger) : BAN::RefPtr<AML::Node>();
if (!value_node)
return {};
const auto value = static_cast<AML::Integer*>(value_node.ptr())->value;
// TODO: optimize for whole byte accesses
for (size_t i = 0; i < field_bit_size; i++)
{
const size_t bit = field_bit_offset + i;
buffer[bit / 8] &= ~(1 << (bit % 8));
buffer[bit / 8] |= ((value >> i) & 1) << (bit % 8);
}
return value_node;
}
static ParseResult parse(AML::ParseContext& context)
{
ASSERT(context.aml_data.size() >= 1);
bool offset_in_bytes;
size_t field_bit_size;
switch (static_cast<AML::Byte>(context.aml_data[0]))
{
case AML::Byte::CreateBitFieldOp:
field_bit_size = 1;
offset_in_bytes = false;
break;
case AML::Byte::CreateByteFieldOp:
field_bit_size = 8;
offset_in_bytes = true;
break;
case AML::Byte::CreateWordFieldOp:
field_bit_size = 16;
offset_in_bytes = true;
break;
case AML::Byte::CreateDWordFieldOp:
field_bit_size = 32;
offset_in_bytes = true;
break;
case AML::Byte::CreateQWordFieldOp:
field_bit_size = 64;
offset_in_bytes = true;
break;
case AML::Byte::ExtOpPrefix:
ASSERT(context.aml_data.size() >= 2);
ASSERT(static_cast<AML::ExtOp>(context.aml_data[1]) == AML::ExtOp::CreateFieldOp);
field_bit_size = 0;
offset_in_bytes = false;
break;
default:
ASSERT_NOT_REACHED();
}
context.aml_data = context.aml_data.slice(1 + (static_cast<AML::Byte>(context.aml_data[0]) == AML::Byte::ExtOpPrefix));
auto buffer_result = AML::parse_object(context);
if (!buffer_result.success())
return ParseResult::Failure;
auto buffer_node = buffer_result.node() ? buffer_result.node()->convert(AML::Node::ConvBuffer) : BAN::RefPtr<AML::Node>();
if (!buffer_node || buffer_node->type != Node::Type::Buffer)
{
AML_ERROR("Buffer source does not evaluate to a Buffer");
return ParseResult::Failure;
}
auto buffer = BAN::RefPtr<AML::Buffer>(static_cast<AML::Buffer*>(buffer_node.ptr()));
auto index_result = AML::parse_object(context);
if (!index_result.success())
return ParseResult::Failure;
auto index_node = index_result.node() ? index_result.node()->convert(AML::Node::ConvInteger) : BAN::RefPtr<AML::Node>();
if (!index_node)
{
AML_ERROR("Failed to parse index for BufferField");
return ParseResult::Failure;
}
if (field_bit_size == 0)
{
auto bit_count_result = AML::parse_object(context);
if (!bit_count_result.success())
return ParseResult::Failure;
auto bit_count_node = bit_count_result.node() ? bit_count_result.node()->convert(AML::Node::ConvInteger) : BAN::RefPtr<AML::Node>();
if (!bit_count_node)
{
AML_ERROR("Failed to parse bit count for BufferField");
return ParseResult::Failure;
}
field_bit_size = static_cast<AML::Integer*>(bit_count_node.ptr())->value;
}
auto field_name = AML::NameString::parse(context.aml_data);
if (!field_name.has_value())
return ParseResult::Failure;
if (field_name->path.empty())
{
AML_ERROR("Empty field name for BufferField");
return ParseResult::Failure;
}
size_t field_bit_offset = static_cast<AML::Integer*>(index_node.ptr())->value;
if (offset_in_bytes)
field_bit_offset *= 8;
auto field = MUST(BAN::RefPtr<BufferField>::create(field_name->path.back(), buffer, field_bit_offset, field_bit_size));
if (!Namespace::root_namespace()->add_named_object(context, field_name.value(), field))
return ParseResult::Success;
#if AML_DEBUG_LEVEL >= 2
field->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("BufferField {} at bit offset {} ({} bits) to { ", name, field_bit_offset, field_bit_size);
buffer->debug_print(0);
AML_DEBUG_PRINT(" }");
}
private:
BAN::RefPtr<AML::Integer> as_integer()
{
ASSERT(buffer);
ASSERT(buffer->type == AML::Node::Type::Buffer || buffer->type == AML::Node::Type::String);
const auto& buffer = (this->buffer->type == AML::Node::Type::Buffer)
? static_cast<AML::Buffer*>(this->buffer.ptr())->buffer
: static_cast<AML::String*>(this->buffer.ptr())->string;
uint64_t value = 0;
// TODO: optimize for whole byte accesses
for (size_t i = 0; i < BAN::Math::min<size_t>(field_bit_size, 64); i++)
{
const size_t bit = field_bit_offset + i;
value |= static_cast<uint64_t>((buffer[bit / 8] >> (bit % 8)) & 1) << i;
}
return MUST(BAN::RefPtr<Integer>::create(value));
}
};
}

View File

@@ -145,19 +145,35 @@ namespace Kernel::ACPI::AML
DataRegionOp = 0x88,
};
static constexpr bool is_digit_char(uint8_t ch)
inline constexpr bool is_digit_char(uint8_t ch)
{
return '0' <= ch && ch <= '9';
}
static constexpr bool is_lead_name_char(uint8_t ch)
inline constexpr bool is_lead_name_char(uint8_t ch)
{
return ('A' <= ch && ch <= 'Z') || ch == '_';
}
static constexpr bool is_name_char(uint8_t ch)
inline constexpr bool is_name_char(uint8_t ch)
{
return is_lead_name_char(ch) || is_digit_char(ch);
}
inline constexpr bool is_name_string_start(uint8_t ch)
{
if (is_lead_name_char(ch))
return true;
switch (static_cast<AML::Byte>(ch))
{
case AML::Byte::RootChar:
case AML::Byte::ParentPrefixChar:
case AML::Byte::MultiNamePrefix:
case AML::Byte::DualNamePrefix:
return true;
default:
return false;
}
}
}

View File

@@ -1,124 +0,0 @@
#pragma once
#include <kernel/ACPI/AML/Buffer.h>
#include <kernel/ACPI/AML/ParseContext.h>
#include <kernel/ACPI/AML/String.h>
namespace Kernel::ACPI::AML
{
struct Concat
{
static ParseResult parse(ParseContext& context)
{
ASSERT(context.aml_data.size() >= 1);
ASSERT(static_cast<Byte>(context.aml_data[0]) == Byte::ConcatOp);
context.aml_data = context.aml_data.slice(1);
auto source1_result = AML::parse_object(context);
if (!source1_result.success())
return ParseResult::Failure;
auto source1 = source1_result.node() ? source1_result.node()->to_underlying() : BAN::RefPtr<AML::Node>();
auto source2_result = AML::parse_object(context);
if (!source2_result.success())
return ParseResult::Failure;
auto source2 = source1_result.node() ? source1_result.node()->to_underlying() : BAN::RefPtr<AML::Node>();
if (!source1 || !source2)
{
AML_ERROR("ConcatOp sources could not be parsed");
return ParseResult::Failure;
}
switch (source1->type)
{
case AML::Node::Type::Integer:
source1 = source1->convert(AML::Node::ConvBuffer);
source2 = source2->convert(AML::Node::ConvBuffer);
break;
case AML::Node::Type::String:
source2 = source2->convert(AML::Node::ConvString);
break;
case AML::Node::Type::Buffer:
source2 = source2->convert(AML::Node::ConvBuffer);
break;
default:
source1 = source1->convert(AML::Node::ConvString);
source2 = source2->convert(AML::Node::ConvString);
break;
}
if (!source1 || !source2)
{
AML_ERROR("ConcatOp sources could not be converted");
return ParseResult::Failure;
}
ASSERT(source1->type == source2->type);
BAN::RefPtr<AML::Node> result;
BAN::Vector<uint8_t>* result_data = nullptr;
BAN::Vector<uint8_t>* source1_data = nullptr;
BAN::Vector<uint8_t>* source2_data = nullptr;
switch (source1->type)
{
case AML::Node::Type::String:
result = MUST(BAN::RefPtr<AML::String>::create());
result_data = &static_cast<AML::String*>(result.ptr())->string;
source1_data = &static_cast<AML::String*>(source1.ptr())->string;
source2_data = &static_cast<AML::String*>(source2.ptr())->string;
break;
case AML::Node::Type::Buffer:
result = MUST(BAN::RefPtr<AML::Buffer>::create());
result_data = &static_cast<AML::Buffer*>(result.ptr())->buffer;
source1_data = &static_cast<AML::Buffer*>(source1.ptr())->buffer;
source2_data = &static_cast<AML::Buffer*>(source2.ptr())->buffer;
break;
default:
ASSERT_NOT_REACHED();
}
ASSERT(result_data && source1_data && source2_data);
MUST(result_data->resize(source1_data->size() + source2_data->size()));
for (size_t i = 0; i < source1_data->size(); i++)
(*result_data)[i] = (*source1_data)[i];
for (size_t i = 0; i < source2_data->size(); i++)
(*result_data)[source1_data->size() + i] = (*source2_data)[i];
#if AML_DEBUG_LEVEL >= 2
AML_DEBUG_PRINT("Concat ");
source1->debug_print(0);
AML_DEBUG_PRINT(", ");
source2->debug_print(0);
AML_DEBUG_PRINTLN("");
#endif
if (context.aml_data.size() < 1)
return ParseResult::Failure;
if (context.aml_data[0] == 0x00)
context.aml_data = context.aml_data.slice(1);
else
{
auto destination_result = AML::parse_object(context);
if (!destination_result.success())
return ParseResult::Failure;
auto destination = destination_result.node();
if (!destination)
{
AML_ERROR("IndexOp failed to resolve destination");
return ParseResult::Failure;
}
if (!destination->store(result))
return ParseResult::Failure;
}
return ParseResult(result);
}
};
}

View File

@@ -1,124 +0,0 @@
#pragma once
#include <kernel/ACPI/AML/Buffer.h>
#include <kernel/ACPI/AML/Integer.h>
#include <kernel/ACPI/AML/ParseContext.h>
#include <kernel/ACPI/AML/String.h>
namespace Kernel::ACPI::AML
{
struct Conversion
{
static ParseResult parse(AML::ParseContext& context)
{
const auto opcode = static_cast<AML::Byte>(context.aml_data[0]);
context.aml_data = context.aml_data.slice(1);
switch (opcode)
{
case AML::Byte::ToBufferOp:
case AML::Byte::ToHexStringOp:
case AML::Byte::ToIntegerOp:
case AML::Byte::ToStringOp:
break;
default:
ASSERT_NOT_REACHED();
}
auto data_result = AML::parse_object(context);
if (!data_result.success())
return ParseResult::Failure;
auto data_node = data_result.node() ? data_result.node()->to_underlying() : BAN::RefPtr<AML::Node>();
if (!data_node)
{
AML_ERROR("Conversion {2H} data could not be evaluated", static_cast<uint8_t>(opcode));
return ParseResult::Failure;
}
if (context.aml_data.size() < 1)
{
AML_ERROR("Conversion {2H} missing target", static_cast<uint8_t>(opcode));
return ParseResult::Failure;
}
BAN::RefPtr<AML::Node> target_node;
if (context.aml_data[0] == 0x00)
context.aml_data = context.aml_data.slice(1);
else
{
auto target_result = AML::parse_object(context);
if (!target_result.success())
return ParseResult::Failure;
target_node = target_result.node();
if (!target_node)
{
AML_ERROR("Conversion {2H} target invalid", static_cast<uint8_t>(opcode));
return ParseResult::Failure;
}
}
BAN::RefPtr<AML::Node> converted;
switch (opcode)
{
case AML::Byte::ToBufferOp:
converted = data_node->convert(AML::Node::ConvBuffer);
break;
case AML::Byte::ToIntegerOp:
converted = data_node->convert(AML::Node::ConvInteger);
break;
case AML::Byte::ToStringOp:
converted = data_node->convert(AML::Node::ConvString);
break;
case AML::Byte::ToHexStringOp:
{
switch (data_node->type)
{
case AML::Node::Type::Integer:
converted = MUST(BAN::RefPtr<AML::String>::create(
MUST(BAN::String::formatted("0x{H}", static_cast<AML::Integer*>(data_node.ptr())->value))
));
break;
case AML::Node::Type::String:
converted = data_node->copy();
break;
case AML::Node::Type::Buffer:
{
const auto& buffer = static_cast<AML::Buffer*>(data_node.ptr())->buffer;
BAN::String temp;
for (size_t i = 0; i < buffer.size(); i++)
{
const char* format = (i == 0) ? "0x{H}" : ", 0x{H}";
MUST(temp.append(MUST(BAN::String::formatted(format, buffer[i]))));
}
converted = MUST(BAN::RefPtr<AML::String>::create(temp));
break;
}
default:
break;
}
break;
}
default:
ASSERT_NOT_REACHED();
}
if (!converted)
{
AML_ERROR("Conversion {2H} could not convert from node type {}", static_cast<uint8_t>(opcode), static_cast<uint8_t>(data_node->type));
return ParseResult::Failure;
}
if (target_node && !target_node->store(converted))
{
AML_ERROR("Conversion {2H} failed to store converted value", static_cast<uint8_t>(opcode));
return ParseResult::Failure;
}
return ParseResult(converted);
}
};
}

View File

@@ -1,65 +0,0 @@
#pragma once
#include <kernel/ACPI/AML/Alias.h>
#include <kernel/ACPI/AML/NamedObject.h>
#include <kernel/ACPI/AML/ParseContext.h>
#include <kernel/ACPI/AML/Register.h>
namespace Kernel::ACPI::AML
{
struct CopyObject
{
static ParseResult parse(ParseContext& context)
{
ASSERT(context.aml_data.size() >= 1);
ASSERT(static_cast<Byte>(context.aml_data[0]) == Byte::CopyObjectOp);
context.aml_data = context.aml_data.slice(1);
auto source_result = AML::parse_object(context);
if (!source_result.success())
return ParseResult::Failure;
auto source = source_result.node()
? source_result.node()->to_underlying()
: BAN::RefPtr<AML::Node>();
if (!source)
{
AML_ERROR("CopyObject source is null");
return ParseResult::Failure;
}
auto destination_result = AML::parse_object(context);
if (!destination_result.success())
return ParseResult::Failure;
auto destination = destination_result.node();
if (!destination)
{
AML_ERROR("CopyObject destination is null");
return ParseResult::Failure;
}
#if AML_DEBUG_LEVEL >= 2
AML_DEBUG_PRINTLN("CopyObject {");
source->debug_print(1);
AML_DEBUG_PRINTLN("");
AML_DEBUG_PRINTLN("} to {");
destination->debug_print(1);
AML_DEBUG_PRINTLN("");
AML_DEBUG_PRINTLN("}");
#endif
switch (destination->type)
{
case AML::Node::Type::Name:
static_cast<AML::Name*>(destination.ptr())->object = source->copy();
return source;
case AML::Node::Type::Register:
static_cast<AML::Register*>(destination.ptr())->value = source->copy();
return source;
default:
ASSERT_NOT_REACHED();
}
}
};
}

View File

@@ -1,59 +0,0 @@
#pragma once
#include <kernel/ACPI/AML/Method.h>
#include <kernel/ACPI/AML/ParseContext.h>
#include <kernel/ACPI/AML/Pkg.h>
#include <kernel/ACPI/AML/Scope.h>
namespace Kernel::ACPI::AML
{
struct Device final : public AML::Scope
{
Device(NameSeg name)
: Scope(Node::Type::Device, name)
{}
BAN::RefPtr<AML::Node> convert(uint8_t) override { return {}; }
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 (!Namespace::root_namespace()->add_named_object(context, name_string.value(), device))
return ParseResult::Success;
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(" {");
Namespace::root_namespace()->for_each_child(scope,
[&](const auto&, const auto& child)
{
child->debug_print(indent + 1);
AML_DEBUG_PRINTLN("");
}
);
AML_DEBUG_PRINT_INDENT(indent);
AML_DEBUG_PRINT("}");
}
};
}

View File

@@ -1,148 +0,0 @@
#pragma once
#include <kernel/ACPI/AML/Bytes.h>
#include <kernel/ACPI/AML/Integer.h>
#include <kernel/ACPI/AML/NamedObject.h>
#include <kernel/ACPI/AML/ParseContext.h>
#include <kernel/ThreadBlocker.h>
#include <kernel/Timer/Timer.h>
namespace Kernel::ACPI::AML
{
struct Event final : public AML::NamedObject
{
BAN::Atomic<uint32_t> signal_count { 0 };
ThreadBlocker thread_blocker;
Event(NameSeg name)
: NamedObject(Node::Type::Event, name)
{}
BAN::RefPtr<AML::Node> convert(uint8_t) override { return {}; }
static ParseResult parse(ParseContext& context)
{
ASSERT(context.aml_data.size() >= 2);
ASSERT(static_cast<AML::Byte>(context.aml_data[0]) == AML::Byte::ExtOpPrefix);
const auto ext_op = static_cast<AML::ExtOp>(context.aml_data[1]);
switch (ext_op)
{
case AML::ExtOp::EventOp:
return parse_event(context);
case AML::ExtOp::ResetOp:
case AML::ExtOp::SignalOp:
case AML::ExtOp::WaitOp:
break;
default:
ASSERT_NOT_REACHED();
}
context.aml_data = context.aml_data.slice(2);
auto event_result = parse_object(context);
if (!event_result.success())
return ParseResult::Failure;
auto general_node = event_result.node();
if (!general_node || general_node->type != Node::Type::Event)
{
AML_ERROR("Release, Wait or Signal does not name an event");
return ParseResult::Failure;
}
auto* event_node = static_cast<AML::Event*>(general_node.ptr());
if (ext_op == AML::ExtOp::WaitOp)
{
auto timeout_result = parse_object(context);
if (!timeout_result.success())
return ParseResult::Failure;
auto timeout_node = timeout_result.node()
? timeout_result.node()->convert(AML::Node::ConvInteger)
: BAN::RefPtr<AML::Node>();
if (!timeout_node)
{
AML_ERROR("Wait timeout does not evaluate to integer");
return ParseResult::Failure;
}
const auto timeout_value = static_cast<AML::Integer*>(timeout_node.ptr())->value;
const uint64_t start_ms = SystemTimer::get().ms_since_boot();
while (true)
{
auto expected = event_node->signal_count.load();
while (true)
{
if (expected == 0)
break;
if (event_node->signal_count.compare_exchange(expected, expected - 1))
return ParseResult(Integer::Constants::Zero);
}
if (timeout_value >= 0xFFFF)
event_node->thread_blocker.block_indefinite();
else
{
const uint64_t current_ms = SystemTimer::get().ms_since_boot();
if (current_ms >= start_ms + timeout_value)
return ParseResult(Integer::Constants::Ones);
event_node->thread_blocker.block_with_timeout_ms(start_ms + timeout_value - current_ms);
}
}
ASSERT_NOT_REACHED();
}
switch (ext_op)
{
case AML::ExtOp::ResetOp:
event_node->signal_count = 0;
break;
case AML::ExtOp::SignalOp:
event_node->signal_count++;
event_node->thread_blocker.unblock();
break;
default:
ASSERT_NOT_REACHED();
}
return ParseResult::Success;
}
virtual void debug_print(int indent) const override
{
AML_DEBUG_PRINT_INDENT(indent);
AML_DEBUG_PRINT("Event ");
name.debug_print();
AML_DEBUG_PRINT(" (Signals: {})", signal_count.load());
}
private:
static ParseResult parse_event(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::EventOp);
context.aml_data = context.aml_data.slice(2);
auto name_string = NameString::parse(context.aml_data);
if (!name_string.has_value())
return ParseResult::Failure;
auto event = MUST(BAN::RefPtr<Event>::create(name_string->path.back()));
if (!Namespace::root_namespace()->add_named_object(context, name_string.value(), event))
return ParseResult::Success;
#if AML_DEBUG_LEVEL >= 2
event->debug_print(0);
AML_DEBUG_PRINTLN("");
#endif
return ParseResult::Success;
}
};
}

View File

@@ -1,283 +0,0 @@
#pragma once
#include <kernel/ACPI/AML/Buffer.h>
#include <kernel/ACPI/AML/Bytes.h>
#include <kernel/ACPI/AML/Integer.h>
#include <kernel/ACPI/AML/ParseContext.h>
#include <kernel/ACPI/AML/String.h>
namespace Kernel::ACPI::AML
{
struct Expression
{
static ParseResult parse(ParseContext& context)
{
ASSERT(context.aml_data.size() >= 1);
switch (static_cast<Byte>(context.aml_data[0]))
{
// unary
case AML::Byte::IncrementOp:
case AML::Byte::DecrementOp:
{
auto opcode = (static_cast<AML::Byte>(context.aml_data[0]) == AML::Byte::IncrementOp) ? AML::Byte::AddOp : AML::Byte::SubtractOp;
context.aml_data = context.aml_data.slice(1);
auto source_result = AML::parse_object(context);
if (!source_result.success())
return ParseResult::Failure;
auto conv_node = source_result.node() ? source_result.node()->convert(AML::Node::ConvInteger) : BAN::RefPtr<AML::Node>();
if (!conv_node)
{
AML_ERROR("UnaryOp source not integer, type {}", static_cast<uint8_t>(source_result.node()->type));
return ParseResult::Failure;
}
auto source_node = static_cast<AML::Integer*>(conv_node.ptr());
if (source_node->constant)
{
AML_ERROR("UnaryOp source is constant");
return ParseResult::Failure;
}
source_node->value += (opcode == AML::Byte::AddOp) ? 1 : -1;
return ParseResult(source_node);
}
case AML::Byte::NotOp:
{
auto source_result = AML::parse_object(context);
if (!source_result.success())
return ParseResult::Failure;
auto source_conv = source_result.node() ? source_result.node()->convert(AML::Node::ConvInteger) : BAN::RefPtr<AML::Node>();
if (!source_conv)
{
AML_ERROR("NotOp source not an integer, type {}",
static_cast<uint8_t>(source_result.node()->type)
);
if (source_result.node())
source_result.node()->debug_print(1);
AML_DEBUG_PRINTLN("");
return ParseResult::Failure;
}
const auto source_value = static_cast<AML::Integer*>(source_conv.ptr())->value;
BAN::RefPtr<AML::Node> target_node;
if (context.aml_data[0] == 0x00)
context.aml_data = context.aml_data.slice(1);
else
{
auto target_result = AML::parse_object(context);
if (!target_result.success())
return ParseResult::Failure;
target_node = target_result.node();
if (!target_node)
{
AML_ERROR("NotOp target invalid");
return ParseResult::Failure;
}
}
auto result_node = MUST(BAN::RefPtr<AML::Integer>::create(~source_value));
if (target_node && !target_node->store(result_node))
{
AML_ERROR("NotOp failed to store result");
return ParseResult::Failure;
}
return ParseResult(result_node);
}
case AML::Byte::LNotOp:
{
context.aml_data = context.aml_data.slice(1);
auto source_result = AML::parse_object(context);
if (!source_result.success())
return ParseResult::Failure;
auto conv_node = source_result.node() ? source_result.node()->convert(AML::Node::ConvInteger) : BAN::RefPtr<AML::Node>();
if (!conv_node)
{
AML_ERROR("UnaryOp source not integer, type {}", static_cast<uint8_t>(source_result.node()->type));
return ParseResult::Failure;
}
auto source_node = static_cast<AML::Integer*>(conv_node.ptr());
if (!source_node)
{
AML_ERROR("Logical NotOp source is not integer");
return ParseResult::Failure;
}
auto result = source_node->value ? Integer::Constants::Zero : Integer::Constants::Ones;
return ParseResult(result);
}
case AML::Byte::AddOp:
case AML::Byte::AndOp:
case AML::Byte::ModOp:
case AML::Byte::MultiplyOp:
case AML::Byte::NandOp:
case AML::Byte::NorOp:
case AML::Byte::OrOp:
case AML::Byte::ShiftLeftOp:
case AML::Byte::ShiftRightOp:
case AML::Byte::SubtractOp:
case AML::Byte::XorOp:
return parse_binary_op(context);
case AML::Byte::LAndOp:
case AML::Byte::LEqualOp:
case AML::Byte::LGreaterOp:
case AML::Byte::LLessOp:
case AML::Byte::LOrOp:
return parse_logical_binary_op(context);
case AML::Byte::DivideOp:
AML_TODO("DivideOp");
return ParseResult::Failure;
default:
ASSERT_NOT_REACHED();
}
}
private:
static ParseResult parse_binary_op(ParseContext& context)
{
auto opcode = static_cast<AML::Byte>(context.aml_data[0]);
context.aml_data = context.aml_data.slice(1);
auto lhs_result = AML::parse_object(context);
if (!lhs_result.success())
return ParseResult::Failure;
auto lhs_conv = lhs_result.node() ? lhs_result.node()->convert(AML::Node::ConvInteger) : BAN::RefPtr<AML::Node>();
if (!lhs_conv)
{
AML_ERROR("BinaryOP {2H} LHS not an integer, type {}",
static_cast<uint8_t>(opcode),
static_cast<uint8_t>(lhs_result.node()->type)
);
if (lhs_result.node())
lhs_result.node()->debug_print(1);
AML_DEBUG_PRINTLN("");
return ParseResult::Failure;
}
const auto lhs_value = static_cast<AML::Integer*>(lhs_conv.ptr())->value;
auto rhs_result = AML::parse_object(context);
if (!rhs_result.success())
return ParseResult::Failure;
auto rhs_conv = rhs_result.node() ? rhs_result.node()->convert(AML::Node::ConvInteger) : BAN::RefPtr<AML::Node>();
if (!rhs_conv)
{
AML_ERROR("BinaryOP {2H} RHS not an integer", static_cast<uint8_t>(opcode));
if (rhs_result.node())
rhs_result.node()->debug_print(1);
AML_DEBUG_PRINTLN("");
return ParseResult::Failure;
}
const auto rhs_value = static_cast<AML::Integer*>(rhs_conv.ptr())->value;
if (context.aml_data.size() < 1)
{
AML_ERROR("BinaryOP {2H} missing target", static_cast<uint8_t>(opcode));
return ParseResult::Failure;
}
BAN::RefPtr<AML::Node> target_node;
if (context.aml_data[0] == 0x00)
context.aml_data = context.aml_data.slice(1);
else
{
auto target_result = AML::parse_object(context);
if (!target_result.success())
return ParseResult::Failure;
target_node = target_result.node();
if (!target_node)
{
AML_ERROR("BinaryOP {2H} target invalid", static_cast<uint8_t>(opcode));
return ParseResult::Failure;
}
}
uint64_t (*func)(uint64_t, uint64_t) = nullptr;
switch (opcode)
{
case AML::Byte::AddOp: func = [](uint64_t a, uint64_t b) { return a + b; }; break;
case AML::Byte::AndOp: func = [](uint64_t a, uint64_t b) { return a & b; }; break;
case AML::Byte::ModOp: func = [](uint64_t a, uint64_t b) { return a % b; }; break;
case AML::Byte::MultiplyOp: func = [](uint64_t a, uint64_t b) { return a * b; }; break;
case AML::Byte::NandOp: func = [](uint64_t a, uint64_t b) { return ~(a & b); }; break;
case AML::Byte::NorOp: func = [](uint64_t a, uint64_t b) { return ~(a | b); }; break;
case AML::Byte::OrOp: func = [](uint64_t a, uint64_t b) { return a | b; }; break;
case AML::Byte::ShiftLeftOp: func = [](uint64_t a, uint64_t b) { return a << b; }; break;
case AML::Byte::ShiftRightOp: func = [](uint64_t a, uint64_t b) { return a >> b; }; break;
case AML::Byte::SubtractOp: func = [](uint64_t a, uint64_t b) { return a - b; }; break;
case AML::Byte::XorOp: func = [](uint64_t a, uint64_t b) { return a ^ b; }; break;
default:
ASSERT_NOT_REACHED();
}
auto result_node = MUST(BAN::RefPtr<AML::Integer>::create(func(lhs_value, rhs_value)));
if (target_node && !target_node->store(result_node))
{
AML_ERROR("BinaryOp {2H} failed to store result", static_cast<uint8_t>(opcode));
return ParseResult::Failure;
}
return ParseResult(result_node);
}
static ParseResult parse_logical_binary_op(ParseContext& context)
{
auto opcode = static_cast<AML::Byte>(context.aml_data[0]);
context.aml_data = context.aml_data.slice(1);
uint8_t mask;
switch (opcode)
{
case AML::Byte::LAndOp:
case AML::Byte::LOrOp:
mask = AML::Node::ConvInteger;
break;
case AML::Byte::LEqualOp:
case AML::Byte::LGreaterOp:
case AML::Byte::LLessOp:
mask = AML::Node::ConvInteger | AML::Node::ConvString | AML::Node::ConvBuffer;
break;
default:
ASSERT_NOT_REACHED();
}
auto lhs_result = AML::parse_object(context);
if (!lhs_result.success())
return ParseResult::Failure;
auto lhs_node = lhs_result.node() ? lhs_result.node()->convert(mask) : BAN::RefPtr<AML::Node>();
if (!lhs_node)
{
AML_TODO("Logical BinaryOP {2H} LHS evaluated to nothing", static_cast<uint8_t>(opcode));
return ParseResult::Failure;
}
auto rhs_result = AML::parse_object(context);
if (!rhs_result.success())
return ParseResult::Failure;
BAN::Optional<bool> result = false;
switch (lhs_node->type)
{
case AML::Node::Type::Integer:
result = static_cast<AML::Integer*>(lhs_node.ptr())->logical_compare(rhs_result.node(), opcode);
break;
case AML::Node::Type::Buffer:
result = static_cast<AML::Buffer*>(lhs_node.ptr())->logical_compare(rhs_result.node(), opcode);
break;
case AML::Node::Type::String:
result = static_cast<AML::String*>(lhs_node.ptr())->logical_compare(rhs_result.node(), opcode);
break;
default:
ASSERT_NOT_REACHED();
}
if (!result.has_value())
return ParseResult::Failure;
return ParseResult(result.value() ? AML::Integer::Constants::Ones : AML::Integer::Constants::Zero);
}
};
}

View File

@@ -1,199 +0,0 @@
#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;
enum class AccessAttrib
{
Normal = 0,
Bytes = 1,
RawBytes = 2,
RawProcessBytes = 3,
};
AccessAttrib access_attrib = AccessAttrib::Normal;
uint8_t access_length = 0;
};
struct FieldElement final : public AML::NamedObject
{
uint64_t bit_offset;
uint64_t bit_count;
FieldRules access_rules;
BAN::RefPtr<OpRegion> op_region;
FieldElement(NameSeg name, uint64_t bit_offset, uint64_t bit_count, FieldRules access_rules)
: NamedObject(Node::Type::FieldElement, name)
, bit_offset(bit_offset)
, bit_count(bit_count)
, access_rules(access_rules)
{}
BAN::RefPtr<AML::Node> convert(uint8_t mask) override
{
if (mask & AML::Node::ConvInteger)
return as_integer();
if (mask & AML::Node::ConvBuffer)
{
AML_TODO("Convert BankFieldElement to Buffer");
return {};
}
if (mask & AML::Node::ConvString)
{
AML_TODO("Convert BankFieldElement to String");
return {};
}
return {};
}
BAN::RefPtr<AML::Node> store(BAN::RefPtr<Node> source) override;
void debug_print(int indent) const override;
private:
BAN::RefPtr<AML::Integer> as_integer();
BAN::Optional<uint64_t> evaluate_internal();
bool store_internal(uint64_t value);
friend struct IndexFieldElement;
friend struct BankFieldElement;
};
struct Field
{
static ParseResult parse(ParseContext& context);
};
struct IndexFieldElement final : public AML::NamedObject
{
uint64_t bit_offset;
uint64_t bit_count;
FieldRules access_rules;
BAN::RefPtr<FieldElement> index_element;
BAN::RefPtr<FieldElement> data_element;
IndexFieldElement(NameSeg name, uint64_t bit_offset, uint64_t bit_count, FieldRules access_rules)
: NamedObject(Node::Type::IndexFieldElement, name)
, bit_offset(bit_offset)
, bit_count(bit_count)
, access_rules(access_rules)
{}
BAN::RefPtr<AML::Node> convert(uint8_t mask) override
{
if (mask & AML::Node::ConvInteger)
if (auto node = as_integer())
return node;
if (mask & AML::Node::ConvBuffer)
{
AML_TODO("convert BankFieldElement to Buffer");
return {};
}
if (mask & AML::Node::ConvString)
{
AML_TODO("convert BankFieldElement to String");
return {};
}
return {};
}
BAN::RefPtr<AML::Node> store(BAN::RefPtr<Node> source) override;
void debug_print(int indent) const override;
private:
BAN::RefPtr<AML::Integer> as_integer();
};
struct IndexField
{
static ParseResult parse(ParseContext& context);
};
struct BankFieldElement final : public AML::NamedObject
{
uint64_t bit_offset;
uint64_t bit_count;
FieldRules access_rules;
BAN::RefPtr<OpRegion> op_region;
BAN::RefPtr<FieldElement> bank_selector;
uint64_t bank_value;
BankFieldElement(NameSeg name, uint64_t bit_offset, uint64_t bit_count, FieldRules access_rules)
: NamedObject(Node::Type::BankFieldElement, name)
, bit_offset(bit_offset)
, bit_count(bit_count)
, access_rules(access_rules)
{}
BAN::RefPtr<AML::Node> convert(uint8_t mask) override
{
if (mask & AML::Node::ConvInteger)
if (auto node = as_integer())
return node;
if (mask & AML::Node::ConvBuffer)
{
AML_TODO("convert BankFieldElement to Buffer");
return {};
}
if (mask & AML::Node::ConvString)
{
AML_TODO("convert BankFieldElement to String");
return {};
}
return {};
}
BAN::RefPtr<AML::Node> store(BAN::RefPtr<Node> source) override;
void debug_print(int indent) const override;
private:
BAN::RefPtr<AML::Integer> as_integer();
};
struct BankField
{
static ParseResult parse(ParseContext& context);
};
}

View File

@@ -1,65 +0,0 @@
#pragma once
#include <BAN/HashMap.h>
#include <kernel/ACPI/AML/Node.h>
#include <kernel/ACPI/AML/ParseContext.h>
#include <kernel/ACPI/AML/Pkg.h>
namespace Kernel::ACPI::AML
{
struct IfElse
{
static ParseResult parse(ParseContext& context)
{
ASSERT(context.aml_data.size() >= 1);
ASSERT(static_cast<Byte>(context.aml_data[0]) == Byte::IfOp);
context.aml_data = context.aml_data.slice(1);
auto if_pkg = AML::parse_pkg(context.aml_data);
if (!if_pkg.has_value())
return ParseResult::Failure;
auto outer_aml_data = context.aml_data;
context.aml_data = if_pkg.value();
auto predicate_result = AML::parse_object(context);
if (!predicate_result.success())
return ParseResult::Failure;
auto predicate_node = predicate_result.node() ? predicate_result.node()->convert(AML::Node::ConvInteger) : BAN::RefPtr<AML::Node>();
if (!predicate_node)
{
AML_ERROR("If predicate is not an integer");
return ParseResult::Failure;
}
const auto predicate_value = static_cast<AML::Integer*>(predicate_node.ptr())->value;
// Else
BAN::ConstByteSpan else_pkg;
if (outer_aml_data.size() >= 1 && static_cast<AML::Byte>(outer_aml_data[0]) == Byte::ElseOp)
{
outer_aml_data = outer_aml_data.slice(1);
auto else_pkg_result = AML::parse_pkg(outer_aml_data);
if (!else_pkg_result.has_value())
return ParseResult::Failure;
else_pkg = else_pkg_result.value();
}
if (predicate_value == 0)
context.aml_data = else_pkg;
while (context.aml_data.size() > 0)
{
auto object_result = AML::parse_object(context);
if (object_result.returned() || object_result.breaked() || object_result.continued())
return object_result;
if (!object_result.success())
return ParseResult::Failure;
}
context.aml_data = outer_aml_data;
return ParseResult::Success;
}
};
}

View File

@@ -1,126 +0,0 @@
#pragma once
#include <kernel/ACPI/AML/Buffer.h>
#include <kernel/ACPI/AML/Node.h>
#include <kernel/ACPI/AML/Package.h>
#include <kernel/ACPI/AML/ParseContext.h>
#include <kernel/ACPI/AML/Reference.h>
#include <kernel/ACPI/AML/Register.h>
namespace Kernel::ACPI::AML
{
struct Index
{
static ParseResult parse(ParseContext& context)
{
ASSERT(context.aml_data.size() >= 1);
ASSERT(static_cast<Byte>(context.aml_data[0]) == Byte::IndexOp);
context.aml_data = context.aml_data.slice(1);
auto source_result = AML::parse_object(context);
if (!source_result.success())
return ParseResult::Failure;
auto source = source_result.node() ? source_result.node()->to_underlying() : BAN::RefPtr<AML::Node>();
if (source && source->type != AML::Node::Type::Package)
source = source->convert(AML::Node::ConvBuffer | AML::Node::ConvInteger | AML::Node::ConvString);
if (!source)
{
AML_ERROR("IndexOp source could not be converted");
return ParseResult::Failure;
}
auto index_result = AML::parse_object(context);
if (!index_result.success())
return ParseResult::Failure;
auto index_node = index_result.node()
? index_result.node()->convert(AML::Node::ConvInteger)
: BAN::RefPtr<AML::Node>();
if (!index_node)
{
AML_ERROR("IndexOp index is not an integer");
return ParseResult::Failure;
}
const auto index = static_cast<AML::Integer*>(index_node.ptr())->value;
BAN::RefPtr<AML::Reference> result;
switch (source->type)
{
case AML::Node::Type::Buffer:
{
auto buffer = BAN::RefPtr<AML::Buffer>(static_cast<AML::Buffer*>(source.ptr()));
if (index >= buffer->buffer.size())
{
AML_ERROR("IndexOp index is out of buffer bounds");
return ParseResult::Failure;
}
auto buffer_field = MUST(BAN::RefPtr<BufferField>::create(NameSeg(""_sv), buffer, index * 8, 8));
result = MUST(BAN::RefPtr<AML::Reference>::create(buffer_field));
break;
}
case AML::Node::Type::Package:
{
auto package = static_cast<AML::Package*>(source.ptr());
if (index >= package->elements.size())
{
AML_ERROR("IndexOp index is out of package bounds");
return ParseResult::Failure;
}
auto package_element = package->elements[index];
if (!package_element)
{
AML_ERROR("IndexOp target is null package element");
return ParseResult::Failure;
}
result = MUST(BAN::RefPtr<AML::Reference>::create(package_element));
break;
}
case AML::Node::Type::String:
{
auto string = BAN::RefPtr<AML::String>(static_cast<AML::String*>(source.ptr()));
if (index >= string->string.size())
{
AML_ERROR("IndexOp index is out of string bounds");
return ParseResult::Failure;
}
auto buffer_field = MUST(BAN::RefPtr<BufferField>::create(NameSeg(""_sv), string, index * 8, 8));
result = MUST(BAN::RefPtr<AML::Reference>::create(buffer_field));
break;
}
default:
AML_ERROR("IndexOp source is not a Buffer, Package, or String");
return ParseResult::Failure;
}
#if AML_DEBUG_LEVEL >= 2
AML_DEBUG_PRINT("Index {}, ", index);
source->debug_print(0);
AML_DEBUG_PRINTLN("");
#endif
if (context.aml_data.size() < 1)
return ParseResult::Failure;
if (context.aml_data[0] == 0x00)
context.aml_data = context.aml_data.slice(1);
else
{
auto destination_result = AML::parse_object(context);
if (!destination_result.success())
return ParseResult::Failure;
auto destination = destination_result.node();
if (!destination)
{
AML_ERROR("IndexOp failed to resolve destination");
return ParseResult::Failure;
}
if (!destination->store(result))
return ParseResult::Failure;
}
return ParseResult(result);
}
};
}

View File

@@ -1,39 +0,0 @@
#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 Integer final : public AML::Node
{
struct Constants
{
// Initialized in Namespace::create_root_namespace
static BAN::RefPtr<Integer> Zero;
static BAN::RefPtr<Integer> One;
static BAN::RefPtr<Integer> Ones;
};
uint64_t value;
const bool constant;
Integer(uint64_t value, bool constant = false);
BAN::Optional<bool> logical_compare(BAN::RefPtr<AML::Node> node, AML::Byte binaryop);
BAN::RefPtr<AML::Node> convert(uint8_t mask) override;
BAN::RefPtr<Node> copy() override;
BAN::RefPtr<AML::Node> store(BAN::RefPtr<AML::Node> store_node) override;
static ParseResult parse(BAN::ConstByteSpan& aml_data);
void debug_print(int indent) const override;
};
}

View File

@@ -1,182 +0,0 @@
#pragma once
#include <BAN/Function.h>
#include <kernel/ACPI/AML/Bytes.h>
#include <kernel/ACPI/AML/Namespace.h>
#include <kernel/ACPI/AML/Namespace.h>
#include <kernel/ACPI/AML/ParseContext.h>
#include <kernel/ACPI/AML/Pkg.h>
#include <kernel/ACPI/AML/Register.h>
#include <kernel/ACPI/AML/Scope.h>
namespace Kernel::ACPI::AML
{
struct Method final : public AML::Scope
{
Kernel::Mutex mutex;
uint8_t arg_count;
bool serialized;
uint8_t sync_level;
BAN::Function<BAN::RefPtr<AML::Node>(ParseContext&)> override_function;
BAN::ConstByteSpan term_list;
Method(AML::NameSeg name, uint8_t arg_count, bool serialized, uint8_t sync_level)
: AML::Scope(Node::Type::Method, name)
, arg_count(arg_count)
, serialized(serialized)
, sync_level(sync_level)
{}
BAN::RefPtr<AML::Node> convert(uint8_t) override { return {}; }
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
));
if (!Namespace::root_namespace()->add_named_object(context, name_string.value(), method))
return ParseResult::Success;
method->term_list = method_pkg.value();
#if AML_DEBUG_LEVEL >= 2
method->debug_print(0);
AML_DEBUG_PRINTLN("");
#endif
return ParseResult::Success;
}
BAN::Optional<BAN::RefPtr<AML::Node>> invoke(
BAN::RefPtr<AML::Node> arg0 = {},
BAN::RefPtr<AML::Node> arg1 = {},
BAN::RefPtr<AML::Node> arg2 = {},
BAN::RefPtr<AML::Node> arg3 = {},
BAN::RefPtr<AML::Node> arg4 = {},
BAN::RefPtr<AML::Node> arg5 = {},
BAN::RefPtr<AML::Node> arg6 = {}
)
{
BAN::Vector<uint8_t> sync_stack;
return invoke_with_sync_stack(sync_stack, arg0, arg1, arg2, arg3, arg4, arg5, arg6);
}
BAN::Optional<BAN::RefPtr<AML::Node>> invoke_with_sync_stack(
BAN::Vector<uint8_t>& current_sync_stack,
BAN::RefPtr<AML::Node> arg0 = {},
BAN::RefPtr<AML::Node> arg1 = {},
BAN::RefPtr<AML::Node> arg2 = {},
BAN::RefPtr<AML::Node> arg3 = {},
BAN::RefPtr<AML::Node> arg4 = {},
BAN::RefPtr<AML::Node> arg5 = {},
BAN::RefPtr<AML::Node> arg6 = {}
)
{
if (serialized && !current_sync_stack.empty() && sync_level < current_sync_stack.back())
{
AML_ERROR("Trying to evaluate method {} with lower sync level than current sync level", scope);
return {};
}
ParseContext context;
context.aml_data = term_list;
context.scope = scope;
context.method_args[0] = MUST(BAN::RefPtr<AML::Register>::create(arg0));
context.method_args[1] = MUST(BAN::RefPtr<AML::Register>::create(arg1));
context.method_args[2] = MUST(BAN::RefPtr<AML::Register>::create(arg2));
context.method_args[3] = MUST(BAN::RefPtr<AML::Register>::create(arg3));
context.method_args[4] = MUST(BAN::RefPtr<AML::Register>::create(arg4));
context.method_args[5] = MUST(BAN::RefPtr<AML::Register>::create(arg5));
context.method_args[6] = MUST(BAN::RefPtr<AML::Register>::create(arg6));
context.sync_stack = BAN::move(current_sync_stack);
for (auto& local : context.method_locals)
local = MUST(BAN::RefPtr<AML::Register>::create());
if (serialized)
{
mutex.lock();
MUST(context.sync_stack.push_back(sync_level));
}
#if AML_DEBUG_LEVEL >= 2
AML_DEBUG_PRINTLN("Evaluating {}", scope);
#endif
BAN::Optional<BAN::RefPtr<AML::Node>> return_value = BAN::RefPtr<AML::Node>();
if (override_function)
return_value = override_function(context);
else
{
while (context.aml_data.size() > 0)
{
auto parse_result = AML::parse_object(context);
if (parse_result.returned())
{
return_value = parse_result.node();
break;
}
if (!parse_result.success())
{
AML_ERROR("Method {} evaluate failed", scope);
return_value = {};
break;
}
}
}
if (return_value.has_value() && return_value.value() && return_value.value()->type == AML::Node::Type::Register)
return_value.value() = static_cast<AML::Register*>(return_value.value().ptr())->value;
while (!context.created_objects.empty())
{
Namespace::root_namespace()->remove_named_object(context.created_objects.back());
context.created_objects.pop_back();
}
if (serialized)
{
context.sync_stack.pop_back();
mutex.unlock();
}
current_sync_stack = BAN::move(context.sync_stack);
return return_value;
}
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("}");
}
};
}

View File

@@ -1,170 +0,0 @@
#pragma once
#include <kernel/ACPI/AML/Bytes.h>
#include <kernel/ACPI/AML/Integer.h>
#include <kernel/ACPI/AML/NamedObject.h>
#include <kernel/ACPI/AML/ParseContext.h>
#include <kernel/Lock/Mutex.h>
#include <kernel/Timer/Timer.h>
namespace Kernel::ACPI::AML
{
struct Mutex final : public AML::NamedObject
{
Kernel::Mutex mutex;
uint8_t sync_level;
bool global;
Mutex(NameSeg name, uint8_t sync_level, bool global = false)
: NamedObject(Node::Type::Mutex, name)
, sync_level(sync_level)
, global(global)
{}
BAN::RefPtr<AML::Node> convert(uint8_t) override { return {}; }
static ParseResult parse(ParseContext& context)
{
ASSERT(context.aml_data.size() >= 2);
ASSERT(static_cast<AML::Byte>(context.aml_data[0]) == AML::Byte::ExtOpPrefix);
switch (static_cast<AML::ExtOp>(context.aml_data[1]))
{
case AML::ExtOp::MutexOp:
return parse_mutex(context);
case AML::ExtOp::AcquireOp:
return parse_acquire(context);
case AML::ExtOp::ReleaseOp:
return parse_release(context);
default:
ASSERT_NOT_REACHED();
}
}
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);
}
private:
static ParseResult parse_mutex(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 (!Namespace::root_namespace()->add_named_object(context, name.value(), mutex))
return ParseResult::Success;
#if AML_DEBUG_LEVEL >= 2
mutex->debug_print(0);
AML_DEBUG_PRINTLN("");
#endif
return ParseResult::Success;
}
static ParseResult parse_acquire(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::AcquireOp);
context.aml_data = context.aml_data.slice(2);
auto mutex_result = AML::parse_object(context);
if (!mutex_result.success() || !mutex_result.node() || mutex_result.node()->type != AML::Node::Type::Mutex)
{
AML_ERROR("Acquire does not name a valid mutex");
return ParseResult::Failure;
}
auto* mutex = static_cast<AML::Mutex*>(mutex_result.node().ptr());
if (mutex->sync_level < context.sync_level())
{
AML_ERROR("Trying to acquire mutex with lower sync level than current sync level");
return ParseResult::Failure;
}
if (context.aml_data.size() < 2)
{
AML_ERROR("Missing timeout value");
return ParseResult::Failure;
}
uint16_t timeout = context.aml_data[0] | (context.aml_data[1] << 8);
context.aml_data = context.aml_data.slice(2);
if (timeout >= 0xFFFF)
mutex->mutex.lock();
else
{
// FIXME: This is a very inefficient way to wait for a mutex
uint64_t wake_time = SystemTimer::get().ms_since_boot() + timeout;
while (!mutex->mutex.try_lock())
{
if (SystemTimer::get().ms_since_boot() >= wake_time)
return ParseResult(Integer::Constants::Ones);
Processor::yield();
}
}
MUST(context.sync_stack.push_back(mutex->sync_level));
return ParseResult(Integer::Constants::Zero);
}
static ParseResult parse_release(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::ReleaseOp);
context.aml_data = context.aml_data.slice(2);
auto mutex_result = AML::parse_object(context);
if (!mutex_result.success() || !mutex_result.node() || mutex_result.node()->type != AML::Node::Type::Mutex)
{
AML_ERROR("Release does not name a valid mutex");
return ParseResult::Failure;
}
if (context.sync_stack.empty())
{
AML_ERROR("Trying to release mutex without having acquired it");
return ParseResult::Failure;
}
auto* mutex = static_cast<AML::Mutex*>(mutex_result.node().ptr());
if (mutex->sync_level != context.sync_level())
{
AML_ERROR("Trying to release mutex with different sync level than current sync level");
return ParseResult::Failure;
}
mutex->mutex.unlock();
context.sync_stack.pop_back();
return ParseResult::Success;
}
};
}

View File

@@ -1,44 +0,0 @@
#pragma once
#include <BAN/HashMap.h>
#include <kernel/ACPI/AML/Names.h>
namespace Kernel::ACPI::AML
{
struct NamedObject : public AML::Node
{
BAN::RefPtr<NamedObject> parent;
NameSeg name;
NamedObject(Node::Type type, NameSeg name) : Node(type), name(name) {}
};
struct Name final : public AML::NamedObject
{
BAN::RefPtr<AML::Node> object;
Name(NameSeg name, BAN::RefPtr<AML::Node> object)
: NamedObject(Node::Type::Name, name), object(BAN::move(object))
{}
BAN::RefPtr<AML::Node> to_underlying() override { return object; }
BAN::RefPtr<AML::Node> convert(uint8_t mask) override
{
ASSERT(object);
return object->convert(mask);
}
BAN::RefPtr<AML::Node> store(BAN::RefPtr<AML::Node> node) override
{
ASSERT(object);
ASSERT(object->type != AML::Node::Type::Reference);
return object->store(node);
}
static ParseResult parse(ParseContext& context);
virtual void debug_print(int indent) const override;
};
}

View File

@@ -1,244 +0,0 @@
#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);
}
BAN::StringView sv() const
{
size_t len = 4;
while (len > 0 && chars[len - 1] == '_')
len--;
return BAN::StringView(chars, len);
}
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;
NameString() = default;
NameString(BAN::StringView str)
{
if (!str.empty() && str.front() == '\\')
{
MUST(prefix.push_back('\\'));
str = str.substring(1);
}
else
{
while (str.size() > 0 && str.front() == '^')
{
MUST(prefix.push_back('^'));
str = str.substring(1);
}
}
while (!str.empty())
{
ASSERT(str[0] != '.');
size_t len = 1;
while (len < str.size() && str[len] != '.')
len++;
ASSERT(len <= 4);
MUST(path.push_back(NameSeg(str.substring(0, len))));
str = str.substring(len);
if (!str.empty())
{
ASSERT(str[0] == '.');
str = str.substring(1);
}
}
}
static bool can_parse(BAN::ConstByteSpan aml_data)
{
if (aml_data.size() == 0)
return false;
switch (static_cast<AML::Byte>(aml_data[0]))
{
case AML::Byte::RootChar:
case AML::Byte::ParentPrefixChar:
case AML::Byte::NullName:
case AML::Byte::DualNamePrefix:
case AML::Byte::MultiNamePrefix:
return true;
default:
return is_lead_name_char(aml_data[0]);
}
}
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);
}
};
namespace Formatter
{
template<typename F>
void print_argument(F putc, const Kernel::ACPI::AML::NameSeg& name_seg, const ValueFormat&)
{
size_t len = 4;
while (len > 0 && name_seg.chars[len - 1] == '_')
len--;
for (size_t i = 0; i < len; i++)
putc(name_seg.chars[i]);
}
template<typename F>
void print_argument(F putc, const Kernel::ACPI::AML::NameString& name_string, const ValueFormat&)
{
print_argument(putc, name_string.prefix, {});
if (!name_string.path.empty())
print_argument(putc, name_string.path.front(), {});
for (size_t i = 1; i < name_string.path.size(); i++)
{
putc('.');
print_argument(putc, name_string.path[i], {});
}
}
}
}

View File

@@ -1,66 +1,64 @@
#pragma once
#include <BAN/Bitcast.h>
#include <BAN/ByteSpan.h>
#include <BAN/Function.h>
#include <BAN/HashMap.h>
#include <kernel/ACPI/AML/Scope.h>
#include <kernel/ACPI/Headers.h>
#include <kernel/Lock/Mutex.h>
#include <BAN/Iteration.h>
#include <kernel/ACPI/AML/Node.h>
namespace Kernel::ACPI::AML
{
struct Namespace final : public AML::Scope
struct Namespace
{
static BAN::RefPtr<AML::Namespace> create_root_namespace();
static BAN::RefPtr<AML::Namespace> root_namespace();
static BAN::RefPtr<AML::Node> debug_node;
BAN_NON_COPYABLE(Namespace);
BAN_NON_MOVABLE(Namespace);
public:
Namespace() = default;
~Namespace();
template<typename F>
static void for_each_child(const AML::NameString& scope, const F& callback)
static BAN::ErrorOr<void> initialize_root_namespace();
static Namespace& root_namespace();
// this has to be called after initalizing ACPI namespace
BAN::ErrorOr<void> initalize_op_regions();
BAN::ErrorOr<void> parse(BAN::ConstByteSpan);
BAN::ErrorOr<Node> evaluate(BAN::StringView);
// returns empty scope if object already exited
BAN::ErrorOr<Scope> add_named_object(const Scope& scope, const NameString& name_string, Node&& node);
BAN::ErrorOr<Scope> add_named_object(const Scope& scope, const NameString& name_string, Reference* reference);
BAN::ErrorOr<void> remove_named_object(const Scope& absolute_path);
BAN::ErrorOr<void> initialize_devices();
// node is nullptr if it is not found
struct FindResult
{
auto canonical_path = root_namespace()->resolve_path(scope, {}, FindMode::ForceAbsolute);
ASSERT(canonical_path.has_value());
for (auto& [path, child] : root_namespace()->m_objects)
{
if (path.size() < canonical_path->size() + 1)
continue;
if (canonical_path->size() != 1 && path[canonical_path->size()] != '.')
continue;
if (path.sv().substring(0, canonical_path->size()) != canonical_path->sv())
continue;
if (path.sv().substring(canonical_path->size() + 1).contains('.'))
continue;
callback(path, child);
}
}
Namespace(NameSeg name) : AML::Scope(Node::Type::Namespace, name) {}
BAN::RefPtr<AML::Node> convert(uint8_t) override { return {}; }
bool parse(const SDTHeader& header);
void debug_print(int indent) const override;
enum class FindMode
{
Normal,
ForceAbsolute,
Scope path;
Reference* node { nullptr };
};
BAN::Optional<BAN::String> resolve_path(const AML::NameString& relative_base, const AML::NameString& relative_path, FindMode mode, bool check_existence = true) const;
BAN::ErrorOr<FindResult> find_named_object(const Scope& scope, const NameString& name_string, bool force_absolute = false);
// Find an object in the namespace. Returns nullptr if the object is not found.
BAN::RefPtr<NamedObject> find_object(const AML::NameString& relative_base, const AML::NameString& relative_path, FindMode mode);
// Add an object to the namespace. Returns false if the parent object could not be added.
bool add_named_object(ParseContext&, const AML::NameString& object_path, BAN::RefPtr<NamedObject> object);
// Remove an object from the namespace. Returns false if the object could not be removed.
bool remove_named_object(const AML::NameString& absolute_path);
BAN::ErrorOr<void> for_each_child(const Scope&, const BAN::Function<BAN::Iteration(BAN::StringView, Reference*)>&);
BAN::ErrorOr<void> for_each_child(const Scope&, const BAN::Function<BAN::Iteration(const Scope&, Reference*)>&);
private:
BAN::HashMap<BAN::String, BAN::RefPtr<NamedObject>> m_objects;
mutable Mutex m_object_mutex;
BAN::ErrorOr<Scope> resolve_path(const Scope& scope, const NameString& name_string);
BAN::ErrorOr<void> initialize_scope(const Scope& scope);
BAN::ErrorOr<void> opregion_call_reg(const Scope& scope, const Node& opregion);
private:
bool m_has_parsed_namespace { false };
BAN::HashMap<Scope, Reference*> m_named_objects;
BAN::HashMap<Scope, uint32_t> m_called_reg_bitmaps;
};
}

View File

@@ -1,115 +1,419 @@
#pragma once
#include <BAN/Array.h>
#include <BAN/ByteSpan.h>
#include <BAN/LinkedList.h>
#include <BAN/NoCopyMove.h>
#include <BAN/Optional.h>
#include <BAN/RefPtr.h>
#include <BAN/StringView.h>
#include <BAN/Vector.h>
#include <kernel/ACPI/AML/Utils.h>
#include <kernel/ACPI/AML/Scope.h>
#include <kernel/ACPI/Headers.h>
#include <kernel/Lock/Mutex.h>
#define AML_DUMP_FUNCTION_CALLS 0
#define AML_ENABLE_DEBUG 1
namespace Kernel::ACPI::AML
{
struct Buffer;
struct Integer;
struct String;
struct Node : public BAN::RefCounted<Node>
struct NameString
{
static uint64_t total_node_count;
enum Conversion : uint8_t
BAN_NON_COPYABLE(NameString);
public:
NameString() = default;
NameString(NameString&& other)
: parts(BAN::move(other.parts))
{}
NameString& operator=(NameString&& other)
{
ConvBuffer = 1 << 0,
ConvBufferField = 1 << 1,
ConvFieldUnit = 1 << 2,
ConvInteger = 1 << 3,
ConvString = 1 << 4,
parts = BAN::move(other.parts);
return *this;
}
static BAN::ErrorOr<NameString> from_string(BAN::StringView name);
BAN::ErrorOr<NameString> copy() const
{
NameString result;
result.base = this->base;
TRY(result.parts.resize(parts.size()));
for (size_t i = 0; i < parts.size(); i++)
result.parts[i] = parts[i];
return result;
}
static constexpr uint32_t base_root = -1;
uint32_t base { 0 };
BAN::Vector<uint32_t> parts;
};
template<typename T1, typename T2>
struct Pair
{
T1 elem1;
T2 elem2;
};
struct Node;
struct ParseContext;
struct Reference;
struct Mutex
{
Kernel::Mutex mutex;
uint8_t sync_level;
bool global_lock;
uint32_t ref_count;
};
struct Buffer
{
uint64_t size;
uint32_t ref_count;
uint8_t bytes[];
};
struct OpRegion
{
GAS::AddressSpaceID address_space;
uint64_t offset;
uint64_t length;
};
struct FieldUnit
{
enum class Type {
Field,
IndexField,
BankField,
};
uint64_t offset;
uint64_t length;
uint8_t flags;
Type type;
union {
struct {
OpRegion opregion;
} field;
struct {
Reference* index;
Reference* data;
} index_field;
struct {
OpRegion opregion;
Reference* bank_selector;
uint64_t bank_value;
} bank_field;
} as;
};
struct Package
{
struct Element
{
struct Location {
NameString name;
Scope scope;
};
bool resolved { true };
union {
Node* node { nullptr };
Location* location;
} value;
};
enum class Type : uint8_t
uint64_t num_elements;
uint32_t ref_count;
Element elements[];
};
struct Node
{
BAN_NON_COPYABLE(Node);
public:
Node() = default;
~Node() { clear(); }
Node(Node&& other) { *this = BAN::move(other); }
Node& operator=(Node&&);
enum class Type
{
None,
BankFieldElement,
Buffer,
BufferField,
Uninitialized,
Debug,
Device,
Event,
FieldElement,
IndexFieldElement,
Integer,
String,
Buffer,
Package,
BufferField,
OpRegion,
FieldUnit,
Event,
Device,
Processor,
PowerResource,
ThermalZone,
Method,
Mutex,
Name,
Namespace,
OpRegion,
Package,
PackageElement,
PowerResource,
Processor,
// FIXME: Index should not be its own type
// parsing index should return references
Index,
Reference,
Register,
String,
ThermalZone,
};
const Type type;
PredefinedScope,
Count
} type { Type::Uninitialized };
Node(Type type) : type(type) { total_node_count++; }
virtual ~Node() { total_node_count--; }
inline bool is_scope() const
{
switch (type)
{
case Type::Device:
case Type::Processor:
case Type::PowerResource:
case Type::ThermalZone:
case Type::PredefinedScope:
return true;
default:
return false;
}
ASSERT_NOT_REACHED();
}
virtual bool is_scope() const { return false; }
union
{
struct {
uint64_t value;
} integer;
Package* package;
Buffer* str_buf;
struct {
Buffer* buffer;
uint64_t bit_offset;
uint64_t bit_count;
} buffer_field;
OpRegion opregion;
FieldUnit field_unit;
struct {
uint32_t signal_count;
} event;
struct {
uint8_t storage[sizeof(Kernel::Mutex)];
const uint8_t* start;
size_t length;
uint8_t arg_count;
BAN::ErrorOr<Node> (*override_func)(const BAN::Array<Reference*, 7>&);
bool serialized;
Mutex* mutex;
} method;
Mutex* mutex;
struct {
Node::Type type;
union {
Buffer* str_buf;
Package* package;
} as;
uint64_t index;
} index;
Reference* reference;
} as;
[[nodiscard]] virtual BAN::RefPtr<AML::Node> to_underlying() { return this; }
[[nodiscard]] virtual BAN::RefPtr<AML::Node> convert(uint8_t mask) = 0;
[[nodiscard]] virtual BAN::RefPtr<Node> copy() { return this; }
[[nodiscard]] virtual BAN::RefPtr<AML::Node> store(BAN::RefPtr<AML::Node>) { AML_TODO("store, type {}", static_cast<uint8_t>(type)); return {}; }
BAN::ErrorOr<Node> copy() const;
virtual void debug_print(int indent) const = 0;
void clear();
};
struct ParseContext;
struct ParseResult
struct Reference
{
static ParseResult Failure;
static ParseResult Success;
enum class Result
{
Success,
Failure,
Returned,
Breaked,
Continued,
};
ParseResult(Result success)
: m_result(success)
{}
ParseResult(Result success, BAN::RefPtr<Node> node)
: m_result(success)
, m_node(BAN::move(node))
{}
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; }
bool returned() const { return m_result == Result::Returned; }
bool breaked() const { return m_result == Result::Breaked; }
bool continued() const { return m_result == Result::Continued; }
BAN::RefPtr<Node> node()
{
return m_node;
}
private:
Result m_result = Result::Failure;
BAN::RefPtr<Node> m_node;
Node node {};
uint32_t ref_count { 1 };
};
ParseResult parse_object(ParseContext& context);
struct ParseContext
{
Scope scope;
BAN::ConstByteSpan aml_data;
uint32_t call_depth { 0 };
BAN::Array<Reference*, 8> locals;
BAN::Array<Reference*, 7> args;
BAN::LinkedList<Scope> created_nodes;
~ParseContext();
BAN::ErrorOr<void> allocate_locals();
};
enum class ExecutionFlow
{
Normal,
Break,
Continue,
Return,
};
using ExecutionFlowResult = Pair<ExecutionFlow, BAN::Optional<Node>>;
enum Conversion : uint8_t
{
ConvInteger = 1,
ConvBuffer = 2,
ConvString = 4,
};
BAN::ErrorOr<Node> parse_node(ParseContext& context, bool return_ref = false);
BAN::ErrorOr<ExecutionFlowResult> parse_node_or_execution_flow(ParseContext& context);
BAN::ErrorOr<NameString> parse_name_string(BAN::ConstByteSpan& aml_data);
BAN::ErrorOr<BAN::ConstByteSpan> parse_pkg(BAN::ConstByteSpan& aml_data);
BAN::ErrorOr<Node> convert_node(Node&& source, uint8_t conversion, size_t max_length);
BAN::ErrorOr<Node> convert_node(Node&& source, const Node& target);
BAN::ErrorOr<Node> evaluate_node(const Scope& node_path, const Node& node);
// If method has no return, it will return <integer 0>
BAN::ErrorOr<Node> method_call(const Scope& scope, const Node& method, BAN::Array<Reference*, 7>&& args, uint32_t call_depth = 0);
}
namespace BAN::Formatter
{
template<typename F>
void print_argument(F putc, const Kernel::ACPI::AML::NameString& name_string, const ValueFormat&)
{
if (name_string.base == Kernel::ACPI::AML::NameString::base_root)
putc('\\');
else for (uint32_t i = 0; i < name_string.base; i++)
putc('^');
for (size_t i = 0; i < name_string.parts.size(); i++) {
if (i != 0)
putc('.');
const char* name_seg = reinterpret_cast<const char*>(&name_string.parts[i]);
putc(name_seg[0]); putc(name_seg[1]); putc(name_seg[2]); putc(name_seg[3]);
}
}
template<typename F>
void print_argument(F putc, const Kernel::ACPI::AML::Buffer& buffer, const ValueFormat&)
{
static constexpr size_t max_elements { 16 };
print(putc, "<buffer '");
if (buffer.size)
print(putc, "{2H}", buffer.bytes[0]);
for (size_t i = 1; i < buffer.size && i < max_elements; i++)
print(putc, " {2H}", buffer.bytes[i]);
if (buffer.size > max_elements)
print(putc, "...");
print(putc, "'>");
}
template<typename F>
void print_argument(F putc, const Kernel::ACPI::AML::Package& package, const ValueFormat&)
{
print(putc, "<package '{} elements'>", package.num_elements);
}
template<typename F>
void print_argument(F putc, const Kernel::ACPI::AML::Node& node, const ValueFormat&)
{
switch (node.type)
{
case Kernel::ACPI::AML::Node::Type::Uninitialized:
print(putc, "<uninitialized>");
break;
case Kernel::ACPI::AML::Node::Type::Debug:
print(putc, "<debug>");
break;
case Kernel::ACPI::AML::Node::Type::Integer:
print(putc, "<integer 0x{H}>", node.as.integer.value);
break;
case Kernel::ACPI::AML::Node::Type::String:
print(putc, "<string '{}'>",
BAN::StringView(
reinterpret_cast<const char*>(node.as.str_buf->bytes),
node.as.str_buf->size
)
);
break;
case Kernel::ACPI::AML::Node::Type::Package:
print(putc, "{}", *node.as.package);
break;
case Kernel::ACPI::AML::Node::Type::Buffer:
print(putc, "{}", *node.as.str_buf);
break;
case Kernel::ACPI::AML::Node::Type::BufferField:
print(putc, "<buffer field '{} bytes, offset 0x{H}, bit count {}'>",
node.as.buffer_field.buffer->size,
node.as.buffer_field.bit_offset,
node.as.buffer_field.bit_count
);
break;
case Kernel::ACPI::AML::Node::Type::OpRegion:
print(putc, "<opregion 'type {2H}, offset 0x{H}, length 0x{H}'>",
static_cast<uint8_t>(node.as.opregion.address_space),
node.as.opregion.offset,
node.as.opregion.length
);
break;
case Kernel::ACPI::AML::Node::Type::FieldUnit:
print(putc, "<field unit ({}), 'offset 0x{H}, length 0x{H}'>",
static_cast<uint8_t>(node.as.field_unit.type),
node.as.field_unit.offset,
node.as.field_unit.length
);
break;
case Kernel::ACPI::AML::Node::Type::Event:
print(putc, "<event '{} signals'>", node.as.event.signal_count);
break;
case Kernel::ACPI::AML::Node::Type::Device:
print(putc, "<device>");
break;
case Kernel::ACPI::AML::Node::Type::Processor:
print(putc, "<processor>");
break;
case Kernel::ACPI::AML::Node::Type::PowerResource:
print(putc, "<power resouce>");
break;
case Kernel::ACPI::AML::Node::Type::ThermalZone:
print(putc, "<thermal zone>");
break;
case Kernel::ACPI::AML::Node::Type::Method:
print(putc, "<method '{} bytes'>", node.as.method.length);
break;
case Kernel::ACPI::AML::Node::Type::Mutex:
print(putc, "<mutex>");
break;
case Kernel::ACPI::AML::Node::Type::Index:
switch (node.as.index.type)
{
case Kernel::ACPI::AML::Node::Type::String:
case Kernel::ACPI::AML::Node::Type::Buffer:
print(putc, "<index {}, {}>", *node.as.index.as.str_buf, node.as.index.index);
break;
case Kernel::ACPI::AML::Node::Type::Package:
print(putc, "<index {}, {}>", *node.as.index.as.package, node.as.index.index);
break;
default:
print(putc, "<index {}??, {}>", (uint32_t)node.as.index.type, node.as.index.index);
break;
}
break;
case Kernel::ACPI::AML::Node::Type::Reference:
print(putc, "<reference {}, {} refs>", node.as.reference->node, node.as.reference->ref_count);
break;
case Kernel::ACPI::AML::Node::Type::PredefinedScope:
print(putc, "<scope>");
break;
case Kernel::ACPI::AML::Node::Type::Count:
ASSERT_NOT_REACHED();
}
}
}

View File

@@ -1,67 +0,0 @@
#pragma once
#include <kernel/ACPI/AML/Device.h>
#include <kernel/ACPI/AML/ParseContext.h>
#include <kernel/ACPI/AML/Processor.h>
#include <kernel/ACPI/AML/ThermalZone.h>
namespace Kernel::ACPI::AML
{
struct Notify
{
static ParseResult parse(ParseContext& context)
{
ASSERT(context.aml_data.size() >= 1);
ASSERT(static_cast<Byte>(context.aml_data[0]) == Byte::NotifyOp);
context.aml_data = context.aml_data.slice(1);
auto object_result = AML::parse_object(context);
if (!object_result.success())
return ParseResult::Failure;
auto object = object_result.node();
if (!object)
{
AML_ERROR("Notify object is null");
return ParseResult::Failure;
}
auto value_result = AML::parse_object(context);
if (!value_result.success())
return ParseResult::Failure;
auto value_node = value_result.node() ? value_result.node()->convert(AML::Node::ConvInteger) : BAN::RefPtr<AML::Node>();
if (!value_node)
{
AML_ERROR("Notify value is not an integer");
return ParseResult::Failure;
}
const auto value = static_cast<AML::Integer*>(value_node.ptr())->value;
BAN::StringView object_type_sv;
BAN::StringView object_name_sv;
switch (object->type)
{
case AML::Node::Type::Device:
object_type_sv = "Device"_sv;
object_name_sv = static_cast<AML::Device*>(object.ptr())->name.sv();
break;
case AML::Node::Type::Processor:
object_type_sv = "Processor"_sv;
object_name_sv = static_cast<AML::Processor*>(object.ptr())->name.sv();
break;
case AML::Node::Type::ThermalZone:
object_type_sv = "ThermalZone"_sv;
object_name_sv = static_cast<AML::ThermalZone*>(object.ptr())->name.sv();
break;
default:
object_type_sv = "Unknown"_sv;
object_name_sv = "????"_sv;
break;
}
AML_TODO("Notify: {} {}: {2H}", object_type_sv, object_name_sv, value);
return ParseResult::Success;
}
};
}

View File

@@ -1,107 +0,0 @@
#pragma once
#include <kernel/ACPI/AML/Integer.h>
#include <kernel/ACPI/AML/ParseContext.h>
#include <kernel/ACPI/AML/Reference.h>
namespace Kernel::ACPI::AML
{
struct ObjectType
{
static ParseResult parse(ParseContext& context)
{
ASSERT(context.aml_data.size() >= 1);
ASSERT(static_cast<Byte>(context.aml_data[0]) == Byte::ObjectTypeOp);
context.aml_data = context.aml_data.slice(1);
auto object_result = AML::parse_object(context);
if (!object_result.success())
return ParseResult::Failure;
auto object = object_result.node()
? object_result.node()->to_underlying()
: BAN::RefPtr<AML::Node>();
if (object && object->type == AML::Node::Type::Reference)
object = static_cast<AML::Reference*>(object.ptr())->node->to_underlying();
uint64_t value = 0;
if (object)
{
switch (object->type)
{
case AML::Node::Type::None:
case AML::Node::Type::Name:
case AML::Node::Type::PackageElement:
case AML::Node::Type::Reference:
case AML::Node::Type::Register:
ASSERT_NOT_REACHED();
case AML::Node::Type::Namespace:
value = 0;
break;
case AML::Node::Type::Integer:
value = 1;
break;
case AML::Node::Type::String:
value = 2;
break;
case AML::Node::Type::Buffer:
value = 3;
break;
case AML::Node::Type::Package:
value = 4;
break;
case AML::Node::Type::FieldElement:
case AML::Node::Type::BankFieldElement:
case AML::Node::Type::IndexFieldElement:
value = 5;
break;
case AML::Node::Type::Device:
value = 6;
break;
case AML::Node::Type::Event:
value = 7;
break;
case AML::Node::Type::Method:
value = 8;
break;
case AML::Node::Type::Mutex:
value = 9;
break;
case AML::Node::Type::OpRegion:
value = 10;
break;
case AML::Node::Type::PowerResource:
value = 11;
break;
case AML::Node::Type::Processor:
value = 12;
break;
case AML::Node::Type::ThermalZone:
value = 13;
break;
case AML::Node::Type::BufferField:
value = 14;
break;
case AML::Node::Type::Debug:
value = 16;
break;
}
}
#if AML_DEBUG_LEVEL >= 2
if (!object)
AML_DEBUG_PRINTLN("ObjectType { null }");
else
{
AML_DEBUG_PRINTLN("ObjectType {");
object->debug_print(1);
AML_DEBUG_PRINTLN("");
}
#endif
return ParseResult(MUST(BAN::RefPtr<AML::Integer>::create(value)));
}
};
}

View File

@@ -0,0 +1,16 @@
#pragma once
#include <kernel/ACPI/AML/Node.h>
namespace Kernel::ACPI::AML
{
BAN::ErrorOr<void> parse_opregion_op(ParseContext& context);
BAN::ErrorOr<void> parse_field_op(ParseContext& context);
BAN::ErrorOr<void> parse_index_field_op(ParseContext& context);
BAN::ErrorOr<void> parse_bank_field_op(ParseContext& context);
BAN::ErrorOr<Node> convert_from_field_unit(const Node& node, uint8_t conversion, size_t max_length);
BAN::ErrorOr<void> store_to_field_unit(const Node& source, const Node& target);
}

View File

@@ -1,168 +0,0 @@
#pragma once
#include <kernel/ACPI/AML/Bytes.h>
#include <kernel/ACPI/AML/Integer.h>
#include <kernel/ACPI/AML/Node.h>
#include <kernel/ACPI/AML/ParseContext.h>
#include <kernel/ACPI/AML/Pkg.h>
#include <kernel/ACPI/AML/Reference.h>
namespace Kernel::ACPI::AML
{
struct PackageElement;
struct Package final : public AML::Node
{
BAN::Vector<BAN::RefPtr<PackageElement>> elements;
AML::NameString scope;
Package(AML::NameString scope)
: Node(Node::Type::Package)
, elements(BAN::move(elements))
, scope(scope)
{}
BAN::RefPtr<AML::Node> convert(uint8_t) override { return {}; }
static ParseResult parse(AML::ParseContext& context);
virtual void debug_print(int indent) const override;
};
struct PackageElement final : public AML::Node
{
BAN::RefPtr<AML::Package> parent;
BAN::RefPtr<AML::Node> element;
AML::NameString unresolved_name;
bool resolved = false;
bool initialized = false;
PackageElement(BAN::RefPtr<AML::Package> parent, BAN::RefPtr<AML::Node> element)
: Node(Node::Type::PackageElement)
, parent(parent)
, element(element)
{
ASSERT(element);
resolved = true;
initialized = true;
}
PackageElement(BAN::RefPtr<AML::Package> parent, AML::NameString unresolved_name)
: Node(Node::Type::PackageElement)
, parent(parent)
, unresolved_name(unresolved_name)
{
resolved = false;
initialized = true;
}
PackageElement(BAN::RefPtr<AML::Package> parent)
: Node(Node::Type::PackageElement)
, parent(parent)
{
resolved = false;
initialized = false;
}
bool resolve()
{
ASSERT(!resolved);
auto object = Namespace::root_namespace()->find_object(parent->scope, unresolved_name, Namespace::FindMode::Normal);
if (!object)
{
AML_ERROR("Failed to resolve reference {} in package {}", unresolved_name, parent->scope);
return false;
}
element = object;
resolved = true;
return true;
}
BAN::RefPtr<AML::Node> convert(uint8_t mask) override
{
if (!initialized)
{
AML_ERROR("Trying to convert uninitialized PackageElement");
return {};
}
if (!resolved && !resolve())
return {};
return element->convert(mask);
}
BAN::RefPtr<AML::Node> to_underlying() override
{
if (!initialized)
{
AML_ERROR("Trying to read uninitialized PackageElement");
return {};
}
if (!resolved && !resolve())
return {};
return element;
}
BAN::RefPtr<AML::Node> store(BAN::RefPtr<AML::Node> node) override
{
if (!initialized)
{
initialized = true;
resolved = true;
}
if (!resolved && !resolve())
return {};
ASSERT(!element || element->type != AML::Node::Type::Reference);
if (node->type == AML::Node::Type::Reference)
element = static_cast<AML::Reference*>(node.ptr())->node;
else
element = node->copy();
return node;
}
static ParseResult parse(AML::ParseContext& context, BAN::RefPtr<AML::Package> package)
{
BAN::RefPtr<AML::PackageElement> element;
if (context.aml_data[0] != 0x00 && AML::NameString::can_parse(context.aml_data))
{
auto name = AML::NameString::parse(context.aml_data);
if (!name.has_value())
return ParseResult::Failure;
element = MUST(BAN::RefPtr<PackageElement>::create(package, name.value()));
}
else
{
auto element_result = AML::parse_object(context);
if (!element_result.success())
return ParseResult::Failure;
element = MUST(BAN::RefPtr<PackageElement>::create(package, element_result.node()));
}
return ParseResult(element);
}
virtual void debug_print(int indent) const override
{
AML_DEBUG_PRINT_INDENT(indent);
AML_DEBUG_PRINTLN("PackageElement {");
if (!initialized)
{
AML_DEBUG_PRINT_INDENT(indent + 1);
AML_DEBUG_PRINT("Uninitialized");
}
else if (!resolved)
{
AML_DEBUG_PRINT_INDENT(indent + 1);
AML_DEBUG_PRINT("Unresolved {}", unresolved_name);
}
else
{
element->debug_print(indent + 1);
}
AML_DEBUG_PRINTLN("");
AML_DEBUG_PRINT_INDENT(indent);
AML_DEBUG_PRINT("}");
}
};
}

View File

@@ -1,30 +0,0 @@
#pragma once
#include <BAN/Array.h>
#include <BAN/ByteSpan.h>
#include <BAN/LinkedList.h>
#include <kernel/ACPI/AML/NamedObject.h>
#include <kernel/ACPI/AML/Namespace.h>
#include <kernel/ACPI/AML/Register.h>
namespace Kernel::ACPI::AML
{
struct ParseContext
{
BAN::ConstByteSpan aml_data;
AML::NameString scope;
// Used for cleaning up on method exit
// NOTE: This uses linked list instead of vector because
// we don't really need large contiguous memory
BAN::LinkedList<AML::NameString> created_objects;
uint8_t sync_level() const { return !sync_stack.empty() ? sync_stack.back() : 0; }
BAN::Vector<uint8_t> sync_stack;
BAN::Array<BAN::RefPtr<Register>, 7> method_args;
BAN::Array<BAN::RefPtr<Register>, 8> method_locals;
};
}

View File

@@ -1,51 +0,0 @@
#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;
}
}

View File

@@ -1,70 +0,0 @@
#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 PowerResource final : public AML::Scope
{
uint8_t system_level;
uint16_t resource_order;
PowerResource(NameSeg name, uint8_t system_level, uint16_t resource_order)
: Scope(Node::Type::PowerResource, name)
, system_level(system_level)
, resource_order(resource_order)
{}
BAN::RefPtr<AML::Node> convert(uint8_t) override { return {}; }
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::PowerResOp);
context.aml_data = context.aml_data.slice(2);
auto opt_power_res_pkg = AML::parse_pkg(context.aml_data);
if (!opt_power_res_pkg.has_value())
return ParseResult::Failure;
auto power_res_pkg = opt_power_res_pkg.value();
auto name = NameString::parse(power_res_pkg);
if (!name.has_value())
return ParseResult::Failure;
if (power_res_pkg.size() < 1)
return ParseResult::Failure;
uint8_t system_level = power_res_pkg[0];
power_res_pkg = power_res_pkg.slice(1);
if (power_res_pkg.size() < 2)
return ParseResult::Failure;
uint16_t resource_order = BAN::little_endian_to_host<uint16_t>(*reinterpret_cast<const uint16_t*>(power_res_pkg.data()));
power_res_pkg = power_res_pkg.slice(2);
auto power_res = MUST(BAN::RefPtr<PowerResource>::create(name->path.back(), system_level, resource_order));
if (!Namespace::root_namespace()->add_named_object(context, name.value(), power_res))
return ParseResult::Failure;
#if AML_DEBUG_LEVEL >= 2
power_res->debug_print(0);
AML_DEBUG_PRINTLN("");
#endif
return power_res->enter_context_and_parse_term_list(context, name.value(), power_res_pkg);
}
virtual void debug_print(int indent) const override
{
AML_DEBUG_PRINT_INDENT(indent);
AML_DEBUG_PRINT("PowerResource {} (SystemLevel {}, ResourceOrder {})", name, system_level, resource_order);
}
};
}

View File

@@ -1,86 +0,0 @@
#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 final : 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(Node::Type::Processor, name)
, id(id)
, pblk_addr(pblk_addr)
, pblk_len(pblk_len)
{}
BAN::RefPtr<AML::Node> convert(uint8_t) override { return {}; }
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 opt_processor_pkg = AML::parse_pkg(context.aml_data);
if (!opt_processor_pkg.has_value())
return ParseResult::Failure;
auto processor_pkg = opt_processor_pkg.value();
auto name = NameString::parse(processor_pkg);
if (!name.has_value())
return ParseResult::Failure;
if (processor_pkg.size() < 1)
return ParseResult::Failure;
uint8_t id = processor_pkg[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[0];
processor_pkg = processor_pkg.slice(1);
auto processor = MUST(BAN::RefPtr<Processor>::create(name->path.back(), id, pblk_addr, pblk_len));
if (!Namespace::root_namespace()->add_named_object(context, name.value(), processor))
return ParseResult::Success;
#if AML_DEBUG_LEVEL >= 2
processor->debug_print(0);
AML_DEBUG_PRINTLN("");
#endif
return processor->enter_context_and_parse_term_list(context, name.value(), processor_pkg);
}
virtual void debug_print(int indent) const override
{
AML_DEBUG_PRINT_INDENT(indent);
AML_DEBUG_PRINTLN("Processor {} (ID: {}, PBlkAddr: 0x{H}, PBlkLen: {}) {", name, id, pblk_addr, pblk_len);
Namespace::root_namespace()->for_each_child(scope,
[&](const auto&, const auto& child)
{
child->debug_print(indent + 1);
AML_DEBUG_PRINTLN("");
}
);
AML_DEBUG_PRINT_INDENT(indent);
AML_DEBUG_PRINT("}");
}
};
}

View File

@@ -1,186 +0,0 @@
#pragma once
#include <kernel/ACPI/AML/Bytes.h>
#include <kernel/ACPI/AML/Integer.h>
#include <kernel/ACPI/AML/Node.h>
#include <kernel/ACPI/AML/Names.h>
#include <kernel/ACPI/AML/String.h>
#include <kernel/ACPI/AML/ParseContext.h>
namespace Kernel::ACPI::AML
{
struct Reference final : public AML::Node
{
BAN::RefPtr<AML::Node> node;
Reference(BAN::RefPtr<AML::Node> node)
: Node(AML::Node::Type::Reference)
, node(node)
{
ASSERT(node);
}
BAN::RefPtr<AML::Node> convert(uint8_t mask) override
{
ASSERT(node);
return node->convert(mask);
}
BAN::RefPtr<AML::Node> store(BAN::RefPtr<AML::Node> value) override
{
ASSERT(node);
return node->store(value);
}
static ParseResult parse(ParseContext& context)
{
ASSERT(context.aml_data.size() >= 1);
bool conditional = false;
switch (static_cast<AML::Byte>(context.aml_data[0]))
{
case AML::Byte::DerefOfOp:
return parse_dereference(context);
case AML::Byte::RefOfOp:
context.aml_data = context.aml_data.slice(1);
conditional = false;
break;
case AML::Byte::ExtOpPrefix:
ASSERT(static_cast<AML::ExtOp>(context.aml_data[1]) == AML::ExtOp::CondRefOfOp);
context.aml_data = context.aml_data.slice(2);
conditional = true;
break;
default:
ASSERT_NOT_REACHED();
}
BAN::RefPtr<AML::Node> object;
if (NameString::can_parse(context.aml_data))
{
auto name = NameString::parse(context.aml_data);
if (!name.has_value())
return ParseResult::Failure;
object = Namespace::root_namespace()->find_object(context.scope, name.value(), Namespace::FindMode::Normal);
}
else
{
auto parse_result = AML::parse_object(context);
if (!parse_result.success())
return ParseResult::Failure;
object = parse_result.node();
}
if (object && object->type == AML::Node::Type::Reference)
object = static_cast<AML::Reference*>(object.ptr())->node;
if (object && object->type == AML::Node::Type::Register)
object = static_cast<AML::Register*>(object.ptr())->value;
if (!conditional)
{
if (!object)
{
AML_ERROR("RefOf failed to resolve reference");
return ParseResult::Failure;
}
auto reference = MUST(BAN::RefPtr<Reference>::create(object));
#if AML_DEBUG_LEVEL >= 2
reference->debug_print(0);
AML_DEBUG_PRINTLN("");
#endif
return ParseResult(reference);
}
if (context.aml_data.size() < 1)
{
AML_ERROR("CondRefOf missing target");
return ParseResult::Failure;
}
BAN::RefPtr<AML::Node> target_node;
if (context.aml_data[0] == 0x00)
context.aml_data = context.aml_data.slice(1);
else
{
auto target_result = AML::parse_object(context);
if (!target_result.success())
return ParseResult::Failure;
target_node = target_result.node();
if (!target_node)
{
AML_ERROR("CondRefOf failed to resolve target");
return ParseResult::Failure;
}
}
#if AML_DEBUG_LEVEL >= 2
AML_DEBUG_PRINT("CondRefOf ");
if (object)
object->debug_print(0);
else
AML_DEBUG_PRINT("null");
AML_DEBUG_PRINTLN("");
#endif
if (!object)
return AML::ParseResult(Integer::Constants::Zero);
if (target_node && !target_node->store(object))
{
AML_ERROR("CondRefOf failed to store into target");
return ParseResult::Failure;
}
return AML::ParseResult(Integer::Constants::Ones);
}
static ParseResult parse_dereference(ParseContext& context)
{
ASSERT(context.aml_data.size() >= 1);
ASSERT(static_cast<Byte>(context.aml_data[0]) == Byte::DerefOfOp);
context.aml_data = context.aml_data.slice(1);
if (context.aml_data.size() >= 1 && static_cast<AML::Byte>(context.aml_data[0]) == AML::Byte::StringPrefix)
{
auto string_result = AML::String::parse(context);
if (!string_result.success())
return ParseResult::Failure;
ASSERT(string_result.node());
auto string = static_cast<AML::String*>(string_result.node().ptr());
AML_TODO("DerefOf String ({})", string->string);
return ParseResult::Failure;
}
else
{
auto parse_result = AML::parse_object(context);
if (!parse_result.success())
return ParseResult::Failure;
auto node = parse_result.node();
if (node && node->type == AML::Node::Type::Register)
node = static_cast<AML::Register*>(node.ptr())->value;
if (!node || node->type != AML::Node::Type::Reference)
{
AML_TODO("DerefOf source is not a Reference, but a {}", node ? static_cast<uint8_t>(node->type) : 999);
return ParseResult::Failure;
}
#if AML_DEBUG_LEVEL >= 2
AML_DEBUG_PRINT("DerefOf ");
node->debug_print(0);
AML_DEBUG_PRINTLN("");
#endif
return ParseResult(static_cast<Reference*>(node.ptr())->node);
}
}
virtual void debug_print(int indent) const override
{
AML_DEBUG_PRINT_INDENT(indent);
AML_DEBUG_PRINTLN("Reference {");
node->debug_print(indent + 1);
AML_DEBUG_PRINTLN("");
AML_DEBUG_PRINT_INDENT(indent);
AML_DEBUG_PRINT("}");
}
};
}

View File

@@ -1,116 +0,0 @@
#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);
}
};
}

View File

@@ -1,23 +0,0 @@
#pragma once
#include <kernel/ACPI/AML/Node.h>
namespace Kernel::ACPI::AML
{
struct Register final : public AML::Node
{
BAN::RefPtr<AML::Node> value;
Register();
Register(BAN::RefPtr<AML::Node> node);
BAN::RefPtr<AML::Node> to_underlying() override { return value->to_underlying(); }
BAN::RefPtr<AML::Node> convert(uint8_t mask) override;
BAN::RefPtr<AML::Node> store(BAN::RefPtr<AML::Node> source) override;
void debug_print(int indent) const override;
};
}

View File

@@ -1,27 +1,76 @@
#pragma once
#include <kernel/ACPI/AML/NamedObject.h>
#include <kernel/ACPI/AML/Names.h>
#include <BAN/Hash.h>
#include <BAN/NoCopyMove.h>
#include <BAN/Vector.h>
namespace Kernel::ACPI::AML
{
struct Scope : public AML::NamedObject
struct Scope
{
AML::NameString scope;
BAN_NON_COPYABLE(Scope);
public:
Scope() = default;
Scope(Scope&& other) { *this = BAN::move(other); }
Scope& operator=(Scope&& other) { parts = BAN::move(other.parts); return *this; }
Scope(Node::Type type, NameSeg name)
: NamedObject(type, name)
{}
BAN::Vector<uint32_t> parts;
virtual bool is_scope() const override { return true; }
BAN::ErrorOr<Scope> copy() const
{
Scope result;
TRY(result.parts.reserve(parts.size()));
for (uint32_t part : parts)
TRY(result.parts.push_back(part));
return result;
}
static ParseResult parse(ParseContext& context);
protected:
ParseResult enter_context_and_parse_term_list(ParseContext& outer_context, const AML::NameString& name, BAN::ConstByteSpan aml_data);
bool operator==(const Scope& other) const
{
if (parts.size() != other.parts.size())
return false;
for (size_t i = 0; i < parts.size(); i++)
if (parts[i] != other.parts[i])
return false;
return true;
}
};
bool initialize_scope(BAN::RefPtr<Scope> scope);
BAN::ErrorOr<void> initialize_scope(const Scope&);
}
namespace BAN
{
template<>
struct hash<Kernel::ACPI::AML::Scope>
{
hash_t operator()(const Kernel::ACPI::AML::Scope& scope) const
{
hash_t hash { 0 };
for (uint32_t part : scope.parts)
hash ^= u32_hash(part);
return hash;
}
};
}
namespace BAN::Formatter
{
template<typename F>
void print_argument(F putc, const Kernel::ACPI::AML::Scope& scope, const ValueFormat&)
{
putc('\\');
for (size_t i = 0; i < scope.parts.size(); i++) {
if (i != 0)
putc('.');
const char* name_seg = reinterpret_cast<const char*>(&scope.parts[i]);
putc(name_seg[0]); putc(name_seg[1]); putc(name_seg[2]); putc(name_seg[3]);
}
}
}

View File

@@ -1,60 +0,0 @@
#pragma once
#include <kernel/ACPI/AML/Buffer.h>
#include <kernel/ACPI/AML/Names.h>
#include <kernel/ACPI/AML/Package.h>
#include <kernel/ACPI/AML/ParseContext.h>
#include <kernel/ACPI/AML/Reference.h>
namespace Kernel::ACPI::AML
{
struct SizeOf
{
static ParseResult parse(ParseContext& context)
{
ASSERT(context.aml_data.size() >= 1);
ASSERT(static_cast<Byte>(context.aml_data[0]) == Byte::SizeOfOp);
context.aml_data = context.aml_data.slice(1);
auto object_result = AML::parse_object(context);
if (!object_result.success())
return ParseResult::Failure;
auto object_node = object_result.node();
if (object_node)
object_node = object_node->to_underlying();
if (!object_node)
{
AML_ERROR("SizeOf object is null");
return ParseResult::Failure;
}
if (object_node->type != AML::Node::Type::Package)
object_node = object_node->convert(AML::Node::ConvBuffer | AML::Node::ConvString);
if (!object_node)
{
AML_ERROR("SizeOf object is not Buffer, String or Package");
return ParseResult::Failure;
}
uint64_t size = 0;
switch (object_node->type)
{
case AML::Node::Type::Buffer:
size = static_cast<AML::Buffer*>(object_node.ptr())->buffer.size();
break;
case AML::Node::Type::String:
size = static_cast<AML::String*>(object_node.ptr())->string.size();
break;
case AML::Node::Type::Package:
size = static_cast<AML::Package*>(object_node.ptr())->elements.size();
break;
default:
ASSERT_NOT_REACHED();
}
return ParseResult(MUST(BAN::RefPtr<Integer>::create(size)));
}
};
}

View File

@@ -1,42 +0,0 @@
#pragma once
#include <kernel/ACPI/AML/Bytes.h>
#include <kernel/ACPI/AML/ParseContext.h>
#include <kernel/Timer/Timer.h>
namespace Kernel::ACPI::AML
{
struct Sleep
{
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::SleepOp);
context.aml_data = context.aml_data.slice(2);
auto sleep_time_result = AML::parse_object(context);
if (!sleep_time_result.success())
return ParseResult::Failure;
auto sleep_time_node = sleep_time_result.node()
? sleep_time_result.node()->convert(AML::Node::ConvInteger)
: BAN::RefPtr<AML::Node>();
if (!sleep_time_node)
{
AML_ERROR("Sleep time cannot be evaluated to an integer");
return ParseResult::Failure;
}
const auto sleep_time_value = static_cast<AML::Integer*>(sleep_time_node.ptr())->value;
#if AML_DEBUG_LEVEL >= 2
AML_DEBUG_PRINTLN("Sleeping for {} ms", sleep_time_value);
#endif
SystemTimer::get().sleep_ms(sleep_time_value);
return ParseResult::Success;
}
};
}

View File

@@ -1,53 +0,0 @@
#pragma once
#include <kernel/ACPI/AML/Bytes.h>
#include <kernel/ACPI/AML/ParseContext.h>
namespace Kernel::ACPI::AML
{
struct Store
{
static ParseResult parse(ParseContext& context)
{
ASSERT(context.aml_data.size() >= 1);
ASSERT(static_cast<Byte>(context.aml_data[0]) == Byte::StoreOp);
context.aml_data = context.aml_data.slice(1);
auto source_result = AML::parse_object(context);
if (!source_result.success())
return ParseResult::Failure;
auto source = source_result.node();
if (!source)
{
AML_ERROR("Store source is null");
return ParseResult::Failure;
}
auto destination_result = AML::parse_object(context);
if (!destination_result.success())
return ParseResult::Failure;
auto destination = destination_result.node();
if (!destination)
{
AML_ERROR("Store destination is null");
return ParseResult::Failure;
}
#if AML_DEBUG_LEVEL >= 2
AML_DEBUG_PRINTLN("Storing {");
source->debug_print(1);
AML_DEBUG_PRINTLN("");
AML_DEBUG_PRINTLN("} to {");
destination->debug_print(1);
AML_DEBUG_PRINTLN("");
AML_DEBUG_PRINTLN("}");
#endif
if (auto stored = destination->store(source))
return ParseResult(stored);
return ParseResult::Failure;
}
};
}

View File

@@ -1,69 +0,0 @@
#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 final : public AML::Node
{
BAN::Vector<uint8_t> string;
String() : Node(Node::Type::String) {}
String(BAN::StringView string)
: Node(Node::Type::String)
{
MUST(this->string.resize(string.size()));
for (size_t i = 0; i < string.size(); i++)
this->string[i] = string[i];
}
BAN::Optional<bool> logical_compare(BAN::RefPtr<AML::Node> node, AML::Byte binaryop);
BAN::RefPtr<AML::Node> convert(uint8_t mask) override;
BAN::RefPtr<AML::Node> copy() override
{
auto new_string = MUST(BAN::RefPtr<AML::String>::create());
MUST(new_string->string.resize(this->string.size()));
for (size_t i = 0; i < this->string.size(); i++)
new_string->string[i] = this->string[i];
return new_string;
}
BAN::RefPtr<AML::Node> store(BAN::RefPtr<AML::Node> node) override
{
ASSERT(node);
auto conv_node = node->convert(AML::Node::ConvString);
if (!conv_node)
{
AML_ERROR("Could not convert to String");
return {};
}
auto* string_node = static_cast<AML::String*>(conv_node.ptr());
MUST(string.resize(string_node->string.size()));
for (size_t i = 0; i < string.size(); i++)
string[i] = string_node->string[i];
return string_node->copy();
}
BAN::StringView string_view() const
{
return BAN::StringView(reinterpret_cast<const char*>(string.data()), string.size());
}
static ParseResult parse(ParseContext& context);
virtual void debug_print(int indent) const override
{
AML_DEBUG_PRINT_INDENT(indent);
AML_DEBUG_PRINT("String \"{}\"", string_view());
}
private:
BAN::RefPtr<AML::Buffer> as_buffer();
};
}

View File

@@ -1,64 +0,0 @@
#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 ThermalZone final : public AML::Scope
{
ThermalZone(NameSeg name)
: Scope(Node::Type::ThermalZone, name)
{}
BAN::RefPtr<AML::Node> convert(uint8_t) override { return {}; }
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::ThermalZoneOp);
context.aml_data = context.aml_data.slice(2);
auto opt_thermal_zone_pkg = AML::parse_pkg(context.aml_data);
if (!opt_thermal_zone_pkg.has_value())
return ParseResult::Failure;
auto thermal_zone_pkg = opt_thermal_zone_pkg.value();
auto name = NameString::parse(thermal_zone_pkg);
if (!name.has_value())
return ParseResult::Failure;
auto thermal_zone = MUST(BAN::RefPtr<ThermalZone>::create(name->path.back()));
if (!Namespace::root_namespace()->add_named_object(context, name.value(), thermal_zone))
return ParseResult::Success;
#if AML_DEBUG_LEVEL >= 2
thermal_zone->debug_print(0);
AML_DEBUG_PRINTLN("");
#endif
return thermal_zone->enter_context_and_parse_term_list(context, name.value(), thermal_zone_pkg);
}
virtual void debug_print(int indent) const override
{
AML_DEBUG_PRINT_INDENT(indent);
AML_DEBUG_PRINT("ThermalZone {} {", name);
Namespace::root_namespace()->for_each_child(scope,
[&](const auto&, const auto& child)
{
child->debug_print(indent + 1);
AML_DEBUG_PRINTLN("");
}
);
AML_DEBUG_PRINT_INDENT(indent);
AML_DEBUG_PRINT("}");
}
};
}

View File

@@ -1,36 +0,0 @@
#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__)

View File

@@ -1,77 +0,0 @@
#pragma once
#include <kernel/ACPI/AML/Node.h>
#include <kernel/ACPI/AML/ParseContext.h>
#include <kernel/ACPI/AML/Pkg.h>
namespace Kernel::ACPI::AML
{
struct While
{
static ParseResult parse(ParseContext& context)
{
ASSERT(context.aml_data.size() >= 1);
AML::Byte opcode = static_cast<Byte>(context.aml_data[0]);
context.aml_data = context.aml_data.slice(1);
switch (opcode)
{
case AML::Byte::BreakOp:
return ParseResult(ParseResult::Result::Breaked);
case AML::Byte::ContinueOp:
return ParseResult(ParseResult::Result::Continued);
case AML::Byte::WhileOp:
break;
default:
ASSERT_NOT_REACHED();
}
auto while_pkg = AML::parse_pkg(context.aml_data);
if (!while_pkg.has_value())
return ParseResult::Failure;
auto outer_aml_data = context.aml_data;
bool breaked = false;
while (!breaked)
{
context.aml_data = while_pkg.value();
auto predicate_result = AML::parse_object(context);
if (!predicate_result.success())
return ParseResult::Failure;
auto predicate_node = predicate_result.node()
? predicate_result.node()->convert(AML::Node::ConvInteger)
: BAN::RefPtr<AML::Node>();
if (!predicate_node)
{
AML_ERROR("While predicate is not an integer");
return ParseResult::Failure;
}
if (!static_cast<AML::Integer*>(predicate_node.ptr())->value)
break;
while (context.aml_data.size() > 0)
{
auto object_result = AML::parse_object(context);
if (object_result.returned())
return ParseResult(ParseResult::Result::Returned, object_result.node());
if (object_result.breaked())
breaked = true;
if (object_result.breaked() || object_result.continued())
break;
if (!object_result.success())
return ParseResult::Failure;
}
}
context.aml_data = outer_aml_data;
return ParseResult::Success;
}
};
}

View File

@@ -1,5 +1,6 @@
#pragma once
#include <BAN/Errors.h>
#include <BAN/Optional.h>
namespace Kernel::ACPI
@@ -22,8 +23,8 @@ namespace Kernel::ACPI
PlatformCommunicationChannel = 0x0A,
};
BAN::Optional<uint64_t> read();
bool write(uint64_t value);
BAN::ErrorOr<uint64_t> read();
BAN::ErrorOr<void> write(uint64_t value);
AddressSpaceID address_space_id;
uint8_t register_bit_width;