mirror of
https://github.com/SerenityOS/serenity.git
synced 2026-11-07 04:29:30 -10:00
LibACPI: Support reading OpRegionOp and FieldOp
Those two always come in pairs so lets do it in one commit. This doesn't yet support evaluating fields as it's not yet needed and would require setting up callbacks from the interpreter. Co-authored-by: RatcheT2497 <[email protected]>
This commit is contained in:
1 parent
cc1e5ef63b
commit
c9e5fa6ada
6 files changed
+174
-2
No files matched your search
@@ -227,6 +227,22 @@ ErrorOr<void> Interpreter::finalize_term_opcode(OpcodeFrame& frame)
|
||||
return {};
|
||||
}
|
||||
|
||||
case Opcode::OpRegionOp: {
|
||||
auto path = TRY(frame.operand(0).as<NameString>());
|
||||
auto region_space = TRY(frame.operand(1).as<u64>());
|
||||
auto region_offset = TRY(frame.operand(2).as<u64>());
|
||||
auto region_length = TRY(frame.operand(3).as<u64>());
|
||||
|
||||
auto node = TRY(try_make_ref_counted<OperationRegionNode>(region_space, region_offset, region_length));
|
||||
TRY(m_scope_frames.last().insert_node(path, node));
|
||||
return {};
|
||||
}
|
||||
|
||||
case Opcode::FieldOp:
|
||||
// NOTE: All the field elements are read as operands, so all we need to do is reset the field offset.
|
||||
m_current_field_offset = 0;
|
||||
return {};
|
||||
|
||||
default:
|
||||
INTERPRETER_ERROR("Unimplemented!", EINVAL, "Unimplemented term opcode {}!", frame.opcode());
|
||||
}
|
||||
@@ -276,6 +292,54 @@ ErrorOr<IterationDecision> Interpreter::read_operand(TableStream& stream, Operan
|
||||
return IterationDecision::Continue;
|
||||
}
|
||||
|
||||
// https://uefi.org/specs/ACPI/6.6/20_AML_Specification.html#fieldelement
|
||||
case OperandType::FieldElement: {
|
||||
#ifndef KERNEL
|
||||
if constexpr (AML_DEBUG)
|
||||
warn("Reading field element...");
|
||||
#endif
|
||||
if (is_lead_name_char(TRY(stream.peek_byte()))) {
|
||||
// NamedField := NameSeg PkgLength
|
||||
auto name_segment_bytes = TRY(stream.read_in_place<u8 const>(4));
|
||||
auto name_segment = TRY(NameSegment::from_bytes(name_segment_bytes));
|
||||
|
||||
auto package_length = TRY(stream.read_package_length());
|
||||
|
||||
auto operation_region_node = TRY(find_node(TRY(top_opcode_frame.operand(1).as<NameString>()), m_scope_frames.last().scope()));
|
||||
if (operation_region_node->type() != NodeType::OperationRegion)
|
||||
INTERPRETER_ERROR("Expected operation region node!", EINVAL, "Expected operation region node, got {}", operation_region_node->kind());
|
||||
|
||||
auto flags = TRY(top_opcode_frame.operand(2).as<u64>());
|
||||
|
||||
DEBUG_LOG(" ({}, {})", name_segment.to_string_view(), package_length);
|
||||
|
||||
auto node = TRY(try_make_ref_counted<FieldNode>(static_ptr_cast<OperationRegionNode>(operation_region_node), flags, m_current_field_offset, package_length));
|
||||
TRY(m_scope_frames.last().scope()->insert_child(name_segment, node));
|
||||
|
||||
m_current_field_offset += package_length;
|
||||
|
||||
TRY(top_opcode_frame.finish_operand(stream.offset()));
|
||||
return IterationDecision::Continue;
|
||||
}
|
||||
|
||||
auto type = TRY(stream.read_value<u8>());
|
||||
DEBUG_LOG(" Type: {:02X}", type);
|
||||
switch (type) {
|
||||
case 0x00: {
|
||||
// ReservedField := 0x00 PkgLength
|
||||
m_current_field_offset += TRY(stream.read_package_length());
|
||||
|
||||
TRY(top_opcode_frame.finish_operand(stream.offset()));
|
||||
return IterationDecision::Continue;
|
||||
}
|
||||
|
||||
default:
|
||||
INTERPRETER_ERROR("Unimplemented field type!", EINVAL, "Unimplemented field type {:02X}!", type);
|
||||
}
|
||||
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
|
||||
case OperandType::TermArg:
|
||||
case OperandType::DataRefObject:
|
||||
DEBUG_LOG("Reading complex object {}...", to_underlying(operand));
|
||||
@@ -384,12 +448,20 @@ ErrorOr<Object> Interpreter::evaluate(NameString const& path)
|
||||
|
||||
ErrorOr<Object> Interpreter::evaluate(NonnullRefPtr<Node> node)
|
||||
{
|
||||
if (node->type() == NodeType::Name) {
|
||||
switch (node->type()) {
|
||||
case NodeType::Name: {
|
||||
auto name_node = static_ptr_cast<NameNode>(node);
|
||||
return name_node->data();
|
||||
}
|
||||
|
||||
INTERPRETER_ERROR("Cannot evaluate node type!", EINVAL, "Node type {} not supported for evaluation!", node->kind());
|
||||
case NodeType::Field:
|
||||
INTERPRETER_ERROR("Field evaluation not supported!", EINVAL, "Evaluating fields is not supported yet!");
|
||||
|
||||
default:
|
||||
INTERPRETER_ERROR("Cannot evaluate node type!", EINVAL, "Node type {} not supported for evaluation!", node->kind());
|
||||
}
|
||||
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
|
||||
ErrorOr<NonnullRefPtr<Node>> Interpreter::create_root_namespace()
|
||||
|
||||
@@ -83,6 +83,8 @@ private:
|
||||
|
||||
State m_state { State::ReadingOpcode };
|
||||
|
||||
u64 m_current_field_offset { 0 };
|
||||
|
||||
AK::Vector<TableStream> m_loaded_tables;
|
||||
Vector<ScopeFrame> m_scope_frames;
|
||||
Vector<OpcodeFrame> m_opcode_frames;
|
||||
|
||||
@@ -65,4 +65,16 @@ ErrorOr<void> NameNode::write_description(StringBuilder& builder)
|
||||
return {};
|
||||
}
|
||||
|
||||
ErrorOr<void> OperationRegionNode::write_description(StringBuilder& builder)
|
||||
{
|
||||
TRY(builder.try_appendff("OperationRegion(Space: {}, Offset: {}, Length: {})", m_space_raw, m_offset, m_length));
|
||||
return {};
|
||||
}
|
||||
|
||||
ErrorOr<void> FieldNode::write_description(StringBuilder& builder)
|
||||
{
|
||||
TRY(builder.try_appendff("Field(Flags: {}, Offset: {}, Length: {})", m_flags, m_offset, m_length));
|
||||
return {};
|
||||
}
|
||||
|
||||
}
|
||||
@@ -24,6 +24,8 @@ enum class NodeType : u8 {
|
||||
Untyped,
|
||||
Scope,
|
||||
Name,
|
||||
OperationRegion,
|
||||
Field,
|
||||
};
|
||||
|
||||
class Node : public AtomicRefCounted<Node>
|
||||
@@ -77,4 +79,64 @@ protected:
|
||||
Object m_data;
|
||||
};
|
||||
|
||||
class OperationRegionNode : public Node {
|
||||
public:
|
||||
OperationRegionNode(u8 region_space, u64 region_offset, u64 region_length)
|
||||
: m_space_raw(region_space)
|
||||
, m_offset(region_offset)
|
||||
, m_length(region_length)
|
||||
{
|
||||
}
|
||||
|
||||
virtual ErrorOr<void> write_description(StringBuilder& builder) override;
|
||||
|
||||
virtual NodeType type() const override { return NodeType::OperationRegion; }
|
||||
virtual StringView kind() const override { return "Operation Region"sv; }
|
||||
|
||||
GenericAddressStructure::AddressSpace space() const
|
||||
{
|
||||
if (m_space_raw >= 0x80)
|
||||
return GenericAddressStructure::AddressSpace::OEMDefined;
|
||||
|
||||
return static_cast<GenericAddressStructure::AddressSpace>(m_space_raw);
|
||||
}
|
||||
|
||||
u64 offset() const { return m_offset; }
|
||||
u64 length() const { return m_length; }
|
||||
|
||||
private:
|
||||
u8 m_space_raw;
|
||||
u64 m_offset;
|
||||
u64 m_length;
|
||||
};
|
||||
|
||||
class FieldNode : public Node {
|
||||
public:
|
||||
FieldNode(NonnullRefPtr<OperationRegionNode> const& operation_region, u8 flags, size_t offset, size_t size)
|
||||
: m_operation_region(operation_region)
|
||||
, m_flags(flags)
|
||||
, m_offset(offset)
|
||||
, m_length(size)
|
||||
{
|
||||
}
|
||||
|
||||
virtual ErrorOr<void> write_description(StringBuilder& builder) override;
|
||||
|
||||
virtual NodeType type() const override { return NodeType::Field; }
|
||||
virtual StringView kind() const override { return "Field"sv; }
|
||||
|
||||
NonnullRefPtr<OperationRegionNode> const& operation_region() const { return m_operation_region; }
|
||||
|
||||
u8 flags() const { return m_flags; }
|
||||
u64 offset() const { return m_offset; }
|
||||
u64 length() const { return m_length; }
|
||||
|
||||
private:
|
||||
NonnullRefPtr<OperationRegionNode> m_operation_region;
|
||||
|
||||
u8 m_flags;
|
||||
u64 m_offset;
|
||||
u64 m_length;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -26,6 +26,24 @@ constexpr static Array<OperandType, 2> WORD_CONST_OPERANDS = { OperandType::Word
|
||||
constexpr static Array<OperandType, 2> DWORD_CONST_OPERANDS = { OperandType::DWordData, OperandType::End };
|
||||
constexpr static Array<OperandType, 2> QWORD_CONST_OPERANDS = { OperandType::QWordData, OperandType::End };
|
||||
|
||||
constexpr static Array<OperandType, 5> OP_REGION_OPERANDS = {
|
||||
OperandType::NameString,
|
||||
OperandType::ByteData,
|
||||
OperandType::TermArg,
|
||||
OperandType::TermArg,
|
||||
OperandType::End,
|
||||
};
|
||||
|
||||
constexpr static Array<OperandType, 7> FIELD_OPERANDS = {
|
||||
OperandType::MarkAsCount,
|
||||
OperandType::PackageLength,
|
||||
OperandType::NameString,
|
||||
OperandType::ByteData,
|
||||
OperandType::RepeatNextBytes,
|
||||
OperandType::FieldElement,
|
||||
OperandType::End,
|
||||
};
|
||||
|
||||
static ErrorOr<ReadonlySpan<OperandType>> get_opcode_operand_template(Opcode opcode)
|
||||
{
|
||||
switch (opcode) {
|
||||
@@ -42,6 +60,10 @@ static ErrorOr<ReadonlySpan<OperandType>> get_opcode_operand_template(Opcode opc
|
||||
return SCOPE_OPERANDS.span();
|
||||
case Opcode::NameOp:
|
||||
return NAME_OPERANDS.span();
|
||||
case Opcode::OpRegionOp:
|
||||
return OP_REGION_OPERANDS.span();
|
||||
case Opcode::FieldOp:
|
||||
return FIELD_OPERANDS.span();
|
||||
|
||||
case Opcode::ZeroOp:
|
||||
case Opcode::OneOp:
|
||||
@@ -84,6 +106,7 @@ bool OpcodeFrame::filter_opcode_for_next_operand(Opcode opcode)
|
||||
case OperandType::WordData:
|
||||
case OperandType::DWordData:
|
||||
case OperandType::QWordData:
|
||||
case OperandType::FieldElement:
|
||||
return false;
|
||||
|
||||
case OperandType::TermArg:
|
||||
|
||||
@@ -21,6 +21,7 @@ enum class OperandType : u8 {
|
||||
DWordData,
|
||||
QWordData,
|
||||
|
||||
FieldElement,
|
||||
TermArg,
|
||||
|
||||
DataRefObject,
|
||||
|
||||
Reference in new issue
Block a user