/* * Copyright (c) 2025, RatcheT2497 * Copyright (c) 2026, Undefine * * SPDX-License-Identifier: BSD-2-Clause */ #include #include #include #ifdef KERNEL # define warnln dbgln #endif namespace ACPI::AML { // https://uefi.org/specs/ACPI/6.6/20_AML_Specification.html#aml-byte-stream-byte-values constexpr static Array EMPTY_OPERANDS = { OperandType::End }; constexpr static Array SCOPE_OPERANDS = { OperandType::PackageLength, OperandType::NameString, OperandType::End }; constexpr static Array NAME_OPERANDS = { OperandType::NameString, OperandType::DataRefObject, OperandType::End }; constexpr static Array BYTE_CONST_OPERANDS = { OperandType::ByteData, OperandType::End }; constexpr static Array WORD_CONST_OPERANDS = { OperandType::WordData, OperandType::End }; constexpr static Array DWORD_CONST_OPERANDS = { OperandType::DWordData, OperandType::End }; constexpr static Array QWORD_CONST_OPERANDS = { OperandType::QWordData, OperandType::End }; constexpr static Array METHOD_OPERANDS = { OperandType::PackageLength, OperandType::NameString, OperandType::ByteData, 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) { case Opcode::BytePrefix: return BYTE_CONST_OPERANDS.span(); case Opcode::WordPrefix: return WORD_CONST_OPERANDS.span(); case Opcode::DWordPrefix: return DWORD_CONST_OPERANDS.span(); case Opcode::QWordPrefix: return QWORD_CONST_OPERANDS.span(); case Opcode::ScopeOp: return SCOPE_OPERANDS.span(); case Opcode::NameOp: return NAME_OPERANDS.span(); case Opcode::MethodOp: return METHOD_OPERANDS.span(); case Opcode::OpRegionOp: return OP_REGION_OPERANDS.span(); case Opcode::FieldOp: return FIELD_OPERANDS.span(); case Opcode::ZeroOp: case Opcode::OneOp: return EMPTY_OPERANDS.span(); default: warnln("ACPI: get_opcode_operand_template: Unknown opcode template: {}!", opcode); return Error::from_string_view_or_print_error_and_return_errno("Unknown opcode template!"sv, EINVAL); } } ErrorOr OpcodeFrame::from_opcode(Opcode opcode, size_t start) { auto operand_template = TRY(get_opcode_operand_template(opcode)); return OpcodeFrame(opcode, TRY(Vector::from_span(operand_template)), start); } ErrorOr OpcodeFrame::root_frame() { return OpcodeFrame({}, TRY(Vector::from_span(EMPTY_OPERANDS)), 0); } OperandType OpcodeFrame::peek_next_operand() { auto operand = m_operand_template[m_operand_template_index]; if (operand == OperandType::MarkAsCount || operand == OperandType::RepeatNextBytes) operand = m_operand_template[m_operand_template_index + 1]; return operand; } bool OpcodeFrame::filter_opcode_for_next_operand(Opcode opcode) { auto pending_operand = peek_next_operand(); switch (pending_operand) { case OperandType::NameString: case OperandType::PackageLength: case OperandType::ByteData: case OperandType::WordData: case OperandType::DWordData: case OperandType::QWordData: case OperandType::FieldElement: return false; case OperandType::TermArg: return term_arg_filter(opcode); case OperandType::DataRefObject: return data_ref_object_filter(opcode); case OperandType::End: return term_filter(opcode); case OperandType::MarkAsCount: case OperandType::RepeatNextBytes: VERIFY_NOT_REACHED(); } VERIFY_NOT_REACHED(); } ErrorOr OpcodeFrame::begin_operand(size_t current_offset) { auto operand = m_operand_template[m_operand_template_index]; if (operand == OperandType::MarkAsCount) { m_counter_value_index = m_operands.size(); } else if (operand == OperandType::RepeatNextBytes) { if (!m_counter.has_value()) { m_counter = TRY(m_operands.at(m_counter_value_index).as()); check_repeat_opcodes(current_offset); } } return peek_next_operand(); } ErrorOr OpcodeFrame::finish_operand(size_t current_offset) { auto operand_type = m_operand_template[m_operand_template_index]; if (operand_type == OperandType::MarkAsCount) { m_operand_template_index += 2; return {}; } if (!check_repeat_opcodes(current_offset)) m_operand_template_index++; return {}; } ErrorOr OpcodeFrame::finish_operand(Object const& operand, size_t current_offset) { TRY(m_operands.try_append(operand)); return finish_operand(current_offset); } bool OpcodeFrame::check_repeat_opcodes(size_t current_offset) { auto operand_type = m_operand_template[m_operand_template_index]; if (operand_type == OperandType::RepeatNextBytes) { if (current_offset >= m_start + m_counter.value()) { m_counter = {}; m_operand_template_index += 2; return true; } return true; } return false; } }