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:
parent
463bb72d24
commit
869f4011a1
|
@ -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
|
||||
|
|
|
@ -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 };
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
|
@ -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));
|
||||
}
|
||||
};
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}
|
|
@ -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("}");
|
||||
}
|
||||
};
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
|
@ -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();
|
||||
|