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:
Bananymous 2024-12-12 07:03:09 +02:00
parent 463bb72d24
commit 869f4011a1
55 changed files with 5230 additions and 5913 deletions

View File

@ -1,16 +1,10 @@
set(KERNEL_SOURCES
font/prefs.psf.o
kernel/ACPI/ACPI.cpp
kernel/ACPI/AML.cpp
kernel/ACPI/AML/Field.cpp
kernel/ACPI/AML/Integer.cpp
kernel/ACPI/AML/NamedObject.cpp
kernel/ACPI/AML/Namespace.cpp
kernel/ACPI/AML/Node.cpp
kernel/ACPI/AML/Package.cpp
kernel/ACPI/AML/Register.cpp
kernel/ACPI/AML/OpRegion.cpp
kernel/ACPI/AML/Scope.cpp
kernel/ACPI/AML/String.cpp
kernel/APIC.cpp
kernel/BootInfo.cpp
kernel/CPUID.cpp

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