Kernel: Add more conversions for AML Integer, Register, String

This commit is contained in:
Bananymous 2024-08-15 20:50:34 +03:00
parent cf970d5914
commit d9b3a4bf77
7 changed files with 295 additions and 192 deletions

View File

@ -3,10 +3,12 @@ set(KERNEL_SOURCES
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/Scope.cpp
kernel/ACPI/AML/String.cpp
kernel/APIC.cpp

View File

@ -23,162 +23,17 @@ namespace Kernel::ACPI::AML
uint64_t value;
const bool constant;
Integer(uint64_t value, bool constant = false)
: Node(Node::Type::Integer)
, value(value)
, constant(constant)
{}
Integer(uint64_t value, bool constant = false);
BAN::Optional<bool> logical_compare(BAN::RefPtr<AML::Node> node, AML::Byte binaryop)
{
auto rhs_node = node ? node->convert(AML::Node::ConvInteger) : BAN::RefPtr<AML::Node>();
if (!rhs_node)
{
AML_ERROR("Integer logical compare RHS cannot be converted to");
return {};
}
const auto rhs_value = static_cast<AML::Integer*>(rhs_node.ptr())->value;
BAN::Optional<bool> logical_compare(BAN::RefPtr<AML::Node> node, AML::Byte binaryop);
switch (binaryop)
{
case AML::Byte::LAndOp: return value && rhs_value;
case AML::Byte::LEqualOp: return value == rhs_value;
case AML::Byte::LGreaterOp: return value > rhs_value;
case AML::Byte::LLessOp: return value < rhs_value;
case AML::Byte::LOrOp: return value || rhs_value;
default:
ASSERT_NOT_REACHED();
}
}
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;
BAN::RefPtr<AML::Node> convert(uint8_t mask) override
{
if (mask & AML::Node::ConvInteger)
return this;
if (mask & AML::Node::ConvBuffer)
{
AML_TODO("Convert Integer to Buffer");
return {};
}
if (mask & AML::Node::ConvBufferField)
{
AML_TODO("Convert Integer to BufferField");
return {};
}
if (mask & AML::Node::ConvFieldUnit)
{
AML_TODO("Convert Integer to FieldUnit");
return {};
}
if (mask & AML::Node::ConvString)
{
AML_TODO("Convert Integer to String");
return {};
}
return {};
}
static ParseResult parse(BAN::ConstByteSpan& aml_data);
BAN::RefPtr<Node> copy() override { return MUST(BAN::RefPtr<Integer>::create(value)); }
BAN::RefPtr<AML::Node> store(BAN::RefPtr<AML::Node> store_node) override
{
if (constant)
{
AML_ERROR("Cannot store to constant integer");
return {};
}
auto conv_node = store_node ? store_node->convert(AML::Node::ConvInteger) : BAN::RefPtr<AML::Node>();
if (!conv_node)
{
AML_ERROR("Cannot store non-integer to integer");
return {};
}
value = static_cast<AML::Integer*>(conv_node.ptr())->value;
return MUST(BAN::RefPtr<AML::Integer>::create(value));
}
static ParseResult parse(BAN::ConstByteSpan& aml_data)
{
switch (static_cast<AML::Byte>(aml_data[0]))
{
case AML::Byte::ZeroOp:
aml_data = aml_data.slice(1);
return ParseResult(Constants::Zero);
case AML::Byte::OneOp:
aml_data = aml_data.slice(1);
return ParseResult(Constants::One);
case AML::Byte::OnesOp:
aml_data = aml_data.slice(1);
return ParseResult(Constants::Ones);
case AML::Byte::BytePrefix:
{
if (aml_data.size() < 2)
return ParseResult::Failure;
const uint8_t value = aml_data[1];
aml_data = aml_data.slice(2);
return ParseResult(MUST(BAN::RefPtr<Integer>::create(value)));
}
case AML::Byte::WordPrefix:
{
if (aml_data.size() < 3)
return ParseResult::Failure;
uint16_t value = 0;
value |= aml_data[1] << 0;
value |= aml_data[2] << 8;
aml_data = aml_data.slice(3);
return ParseResult(MUST(BAN::RefPtr<Integer>::create(value)));
}
case AML::Byte::DWordPrefix:
{
if (aml_data.size() < 5)
return ParseResult::Failure;
uint32_t value = 0;
value |= static_cast<uint32_t>(aml_data[1]) << 0;
value |= static_cast<uint32_t>(aml_data[2]) << 8;
value |= static_cast<uint32_t>(aml_data[3]) << 16;
value |= static_cast<uint32_t>(aml_data[4]) << 24;
aml_data = aml_data.slice(5);
return ParseResult(MUST(BAN::RefPtr<Integer>::create(value)));
}
case AML::Byte::QWordPrefix:
{
if (aml_data.size() < 9)
return ParseResult::Failure;
uint64_t value = 0;
value |= static_cast<uint64_t>(aml_data[1]) << 0;
value |= static_cast<uint64_t>(aml_data[2]) << 8;
value |= static_cast<uint64_t>(aml_data[3]) << 16;
value |= static_cast<uint64_t>(aml_data[4]) << 24;
value |= static_cast<uint64_t>(aml_data[5]) << 32;
value |= static_cast<uint64_t>(aml_data[6]) << 40;
value |= static_cast<uint64_t>(aml_data[7]) << 48;
value |= static_cast<uint64_t>(aml_data[8]) << 56;
aml_data = aml_data.slice(9);
return ParseResult(MUST(BAN::RefPtr<Integer>::create(value)));
}
default:
ASSERT_NOT_REACHED();
}
}
void debug_print(int indent) const override
{
AML_DEBUG_PRINT_INDENT(indent);
if (!constant)
AML_DEBUG_PRINT("0x{H}", value);
else
{
AML_DEBUG_PRINT("Const ");
if (value == Constants::Zero->value)
AML_DEBUG_PRINT("Zero");
else if (value == Constants::One->value)
AML_DEBUG_PRINT("One");
else if (value == Constants::Ones->value)
AML_DEBUG_PRINT("Ones");
else
ASSERT_NOT_REACHED();
}
}
void debug_print(int indent) const override;
};
}

View File

@ -9,46 +9,13 @@ namespace Kernel::ACPI::AML
{
BAN::RefPtr<AML::Node> value;
Register()
: Node(Node::Type::Register)
{}
Register(BAN::RefPtr<AML::Node> value)
: Node(Node::Type::Register)
, value(value)
{}
Register();
Register(BAN::RefPtr<AML::Node> node);
BAN::RefPtr<AML::Node> convert(uint8_t mask) override
{
if (!value)
{
AML_ERROR("Trying to convert null Register");
return {};
}
return value->convert(mask);
}
BAN::RefPtr<AML::Node> convert(uint8_t mask) override;
BAN::RefPtr<AML::Node> store(BAN::RefPtr<AML::Node> source) override;
BAN::RefPtr<AML::Node> store(BAN::RefPtr<AML::Node> source) override
{
if (value && value->type == AML::Node::Type::Reference)
return value->store(source);
value = source->copy();
return value;
}
void debug_print(int indent) const override
{
AML_DEBUG_PRINT_INDENT(indent);
if (!value)
AML_DEBUG_PRINT("Register { No value }");
else
{
AML_DEBUG_PRINTLN("Register { ");
value->debug_print(indent + 1);
AML_DEBUG_PRINTLN("");
AML_DEBUG_PRINT_INDENT(indent);
AML_DEBUG_PRINT(" }");
}
}
void debug_print(int indent) const override;
};
}

View File

@ -24,6 +24,31 @@ namespace Kernel::ACPI::AML
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());

View File

@ -0,0 +1,180 @@
#include <kernel/ACPI/AML/Buffer.h>
#include <kernel/ACPI/AML/Integer.h>
#include <kernel/ACPI/AML/String.h>
namespace Kernel::ACPI
{
AML::Integer::Integer(uint64_t value, bool constant)
: Node(Node::Type::Integer)
, value(value)
, constant(constant)
{}
BAN::Optional<bool> AML::Integer::logical_compare(BAN::RefPtr<AML::Node> node, AML::Byte binaryop)
{
auto rhs_node = node ? node->convert(AML::Node::ConvInteger) : BAN::RefPtr<AML::Node>();
if (!rhs_node)
{
AML_ERROR("Integer logical compare RHS cannot be converted to");
return {};
}
const auto rhs_value = static_cast<AML::Integer*>(rhs_node.ptr())->value;
switch (binaryop)
{
case AML::Byte::LAndOp: return value && rhs_value;
case AML::Byte::LEqualOp: return value == rhs_value;
case AML::Byte::LGreaterOp: return value > rhs_value;
case AML::Byte::LLessOp: return value < rhs_value;
case AML::Byte::LOrOp: return value || rhs_value;
default:
ASSERT_NOT_REACHED();
}
}
BAN::RefPtr<AML::Node> AML::Integer::convert(uint8_t mask)
{
if (mask & AML::Node::ConvInteger)
return this;
if (mask & AML::Node::ConvBuffer)
{
auto buffer = MUST(BAN::RefPtr<AML::Buffer>::create());
MUST(buffer->buffer.resize(8));
for (size_t i = 0; i < 8; i++)
buffer->buffer[i] = (value >> (56 - i * 8)) & 0xFF;
return buffer;
}
if (mask & AML::Node::ConvBufferField)
{
AML_TODO("Convert Integer to BufferField");
return {};
}
if (mask & AML::Node::ConvFieldUnit)
{
AML_TODO("Convert Integer to FieldUnit");
return {};
}
if (mask & AML::Node::ConvString)
{
constexpr auto get_hex_char =
[](uint8_t nibble)
{
return (nibble < 10 ? '0' : 'A' - 10) + nibble;
};
auto string = MUST(BAN::RefPtr<AML::String>::create());
MUST(string->string.resize(16));
for (size_t i = 0; i < 16; i++)
string->string[i] = get_hex_char((value >> (60 - i * 4)) & 0xF);
return string;
}
return {};
}
BAN::RefPtr<AML::Node> AML::Integer::copy()
{
return MUST(BAN::RefPtr<Integer>::create(value));
}
BAN::RefPtr<AML::Node> AML::Integer::store(BAN::RefPtr<AML::Node> store_node)
{
if (constant)
{
AML_ERROR("Cannot store to constant integer");
return {};
}
auto conv_node = store_node ? store_node->convert(AML::Node::ConvInteger) : BAN::RefPtr<AML::Node>();
if (!conv_node)
{
AML_ERROR("Cannot store non-integer to integer");
return {};
}
value = static_cast<AML::Integer*>(conv_node.ptr())->value;
return MUST(BAN::RefPtr<AML::Integer>::create(value));
}
AML::ParseResult AML::Integer::parse(BAN::ConstByteSpan& aml_data)
{
switch (static_cast<AML::Byte>(aml_data[0]))
{
case AML::Byte::ZeroOp:
aml_data = aml_data.slice(1);
return ParseResult(Constants::Zero);
case AML::Byte::OneOp:
aml_data = aml_data.slice(1);
return ParseResult(Constants::One);
case AML::Byte::OnesOp:
aml_data = aml_data.slice(1);
return ParseResult(Constants::Ones);
case AML::Byte::BytePrefix:
{
if (aml_data.size() < 2)
return ParseResult::Failure;
const uint8_t value = aml_data[1];
aml_data = aml_data.slice(2);
return ParseResult(MUST(BAN::RefPtr<Integer>::create(value)));
}
case AML::Byte::WordPrefix:
{
if (aml_data.size() < 3)
return ParseResult::Failure;
uint16_t value = 0;
value |= aml_data[1] << 0;
value |= aml_data[2] << 8;
aml_data = aml_data.slice(3);
return ParseResult(MUST(BAN::RefPtr<Integer>::create(value)));
}
case AML::Byte::DWordPrefix:
{
if (aml_data.size() < 5)
return ParseResult::Failure;
uint32_t value = 0;
value |= static_cast<uint32_t>(aml_data[1]) << 0;
value |= static_cast<uint32_t>(aml_data[2]) << 8;
value |= static_cast<uint32_t>(aml_data[3]) << 16;
value |= static_cast<uint32_t>(aml_data[4]) << 24;
aml_data = aml_data.slice(5);
return ParseResult(MUST(BAN::RefPtr<Integer>::create(value)));
}
case AML::Byte::QWordPrefix:
{
if (aml_data.size() < 9)
return ParseResult::Failure;
uint64_t value = 0;
value |= static_cast<uint64_t>(aml_data[1]) << 0;
value |= static_cast<uint64_t>(aml_data[2]) << 8;
value |= static_cast<uint64_t>(aml_data[3]) << 16;
value |= static_cast<uint64_t>(aml_data[4]) << 24;
value |= static_cast<uint64_t>(aml_data[5]) << 32;
value |= static_cast<uint64_t>(aml_data[6]) << 40;
value |= static_cast<uint64_t>(aml_data[7]) << 48;
value |= static_cast<uint64_t>(aml_data[8]) << 56;
aml_data = aml_data.slice(9);
return ParseResult(MUST(BAN::RefPtr<Integer>::create(value)));
}
default:
ASSERT_NOT_REACHED();
}
}
void AML::Integer::debug_print(int indent) const
{
AML_DEBUG_PRINT_INDENT(indent);
if (!constant)
AML_DEBUG_PRINT("0x{H}", value);
else
{
AML_DEBUG_PRINT("Const ");
if (value == Constants::Zero->value)
AML_DEBUG_PRINT("Zero");
else if (value == Constants::One->value)
AML_DEBUG_PRINT("One");
else if (value == Constants::Ones->value)
AML_DEBUG_PRINT("Ones");
else
ASSERT_NOT_REACHED();
}
}
}

View File

@ -0,0 +1,71 @@
#include <kernel/ACPI/AML/Reference.h>
#include <kernel/ACPI/AML/Register.h>
namespace Kernel::ACPI
{
AML::Register::Register()
: Node(Node::Type::Register)
{}
AML::Register::Register(BAN::RefPtr<AML::Node> node)
: Node(Node::Type::Register)
{
if (!node)
{
value = node;
return;
}
while (node)
{
if (node->type == AML::Node::Type::Reference)
node = static_cast<AML::Reference*>(node.ptr())->node;
else if (node)
node = node->copy();
if (node->type == AML::Node::Type::Register)
{
node = static_cast<AML::Register*>(node.ptr())->value;
continue;
}
break;
}
ASSERT(node);
value = node;
}
BAN::RefPtr<AML::Node> AML::Register::convert(uint8_t mask)
{
if (!value)
{
AML_ERROR("Trying to convert null Register");
return {};
}
return value->convert(mask);
}
BAN::RefPtr<AML::Node> AML::Register::store(BAN::RefPtr<AML::Node> source)
{
if (source && source->type == AML::Node::Type::Register)
source = static_cast<AML::Register*>(source.ptr())->value;
if (value && value->type == AML::Node::Type::Reference)
return value->store(source);
value = source->copy();
return value;
}
void AML::Register::debug_print(int indent) const
{
AML_DEBUG_PRINT_INDENT(indent);
if (!value)
AML_DEBUG_PRINT("Register { No value }");
else
{
AML_DEBUG_PRINTLN("Register { ");
value->debug_print(indent + 1);
AML_DEBUG_PRINTLN("");
AML_DEBUG_PRINT_INDENT(indent);
AML_DEBUG_PRINT(" }");
}
}
}

View File

@ -33,8 +33,11 @@ namespace Kernel::ACPI::AML
return this;
if (mask & AML::Node::ConvInteger)
{
AML_TODO("Convert String to Integer");
return {};
// Apparently this is what NT does, but its definitely not spec compliant :D
uint64_t value = 0;
const size_t bytes = BAN::Math::min<size_t>(string.size(), sizeof(value));
memcpy(&value, string.data(), bytes);
return MUST(BAN::RefPtr<AML::Integer>::create(value));
}
if (mask & AML::Node::ConvBuffer)
return as_buffer();