diff --git a/Userland/Libraries/LibACPI/Interpreter.cpp b/Userland/Libraries/LibACPI/Interpreter.cpp index e9b17124711..92a5ef36af7 100644 --- a/Userland/Libraries/LibACPI/Interpreter.cpp +++ b/Userland/Libraries/LibACPI/Interpreter.cpp @@ -227,6 +227,22 @@ ErrorOr Interpreter::finalize_term_opcode(OpcodeFrame& frame) return {}; } + case Opcode::OpRegionOp: { + auto path = TRY(frame.operand(0).as()); + auto region_space = TRY(frame.operand(1).as()); + auto region_offset = TRY(frame.operand(2).as()); + auto region_length = TRY(frame.operand(3).as()); + + auto node = TRY(try_make_ref_counted(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 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(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()), 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()); + + DEBUG_LOG(" ({}, {})", name_segment.to_string_view(), package_length); + + auto node = TRY(try_make_ref_counted(static_ptr_cast(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()); + 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 Interpreter::evaluate(NameString const& path) ErrorOr Interpreter::evaluate(NonnullRefPtr node) { - if (node->type() == NodeType::Name) { + switch (node->type()) { + case NodeType::Name: { auto name_node = static_ptr_cast(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> Interpreter::create_root_namespace() diff --git a/Userland/Libraries/LibACPI/Interpreter.h b/Userland/Libraries/LibACPI/Interpreter.h index a323dba2d82..abe12e8d5b4 100644 --- a/Userland/Libraries/LibACPI/Interpreter.h +++ b/Userland/Libraries/LibACPI/Interpreter.h @@ -83,6 +83,8 @@ private: State m_state { State::ReadingOpcode }; + u64 m_current_field_offset { 0 }; + AK::Vector m_loaded_tables; Vector m_scope_frames; Vector m_opcode_frames; diff --git a/Userland/Libraries/LibACPI/Node.cpp b/Userland/Libraries/LibACPI/Node.cpp index 906a35a1b84..7354c717e0c 100644 --- a/Userland/Libraries/LibACPI/Node.cpp +++ b/Userland/Libraries/LibACPI/Node.cpp @@ -65,4 +65,16 @@ ErrorOr NameNode::write_description(StringBuilder& builder) return {}; } +ErrorOr OperationRegionNode::write_description(StringBuilder& builder) +{ + TRY(builder.try_appendff("OperationRegion(Space: {}, Offset: {}, Length: {})", m_space_raw, m_offset, m_length)); + return {}; +} + +ErrorOr FieldNode::write_description(StringBuilder& builder) +{ + TRY(builder.try_appendff("Field(Flags: {}, Offset: {}, Length: {})", m_flags, m_offset, m_length)); + return {}; +} + } diff --git a/Userland/Libraries/LibACPI/Node.h b/Userland/Libraries/LibACPI/Node.h index eff25916500..cb6e8333a60 100644 --- a/Userland/Libraries/LibACPI/Node.h +++ b/Userland/Libraries/LibACPI/Node.h @@ -24,6 +24,8 @@ enum class NodeType : u8 { Untyped, Scope, Name, + OperationRegion, + Field, }; class Node : public AtomicRefCounted @@ -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 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(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 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 write_description(StringBuilder& builder) override; + + virtual NodeType type() const override { return NodeType::Field; } + virtual StringView kind() const override { return "Field"sv; } + + NonnullRefPtr 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 m_operation_region; + + u8 m_flags; + u64 m_offset; + u64 m_length; +}; + } diff --git a/Userland/Libraries/LibACPI/OpcodeFrame.cpp b/Userland/Libraries/LibACPI/OpcodeFrame.cpp index 78420d294e4..fc2b9a37b18 100644 --- a/Userland/Libraries/LibACPI/OpcodeFrame.cpp +++ b/Userland/Libraries/LibACPI/OpcodeFrame.cpp @@ -26,6 +26,24 @@ constexpr static Array WORD_CONST_OPERANDS = { OperandType::Word constexpr static Array DWORD_CONST_OPERANDS = { OperandType::DWordData, OperandType::End }; constexpr static Array QWORD_CONST_OPERANDS = { OperandType::QWordData, OperandType::End }; +constexpr static Array OP_REGION_OPERANDS = { + OperandType::NameString, + OperandType::ByteData, + OperandType::TermArg, + OperandType::TermArg, + OperandType::End, +}; + +constexpr static Array FIELD_OPERANDS = { + OperandType::MarkAsCount, + OperandType::PackageLength, + OperandType::NameString, + OperandType::ByteData, + OperandType::RepeatNextBytes, + OperandType::FieldElement, + OperandType::End, +}; + static ErrorOr> get_opcode_operand_template(Opcode opcode) { switch (opcode) { @@ -42,6 +60,10 @@ static ErrorOr> 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: diff --git a/Userland/Libraries/LibACPI/OpcodeFrame.h b/Userland/Libraries/LibACPI/OpcodeFrame.h index 8a8120d9f3a..a51445feafe 100644 --- a/Userland/Libraries/LibACPI/OpcodeFrame.h +++ b/Userland/Libraries/LibACPI/OpcodeFrame.h @@ -21,6 +21,7 @@ enum class OperandType : u8 { DWordData, QWordData, + FieldElement, TermArg, DataRefObject,