Files
serenity/Userland/Libraries/LibACPI/OpcodeFrame.cpp
T
UndefineandRatcheT2497 70f7715bca LibACPI: Add support for reading methods
For now just create a node, but don't actually do anything with the
body as it's not needed for now.

Co-authored-by: RatcheT2497 <[email protected]>
2026-11-01 15:08:28 +01:00

192 lines
5.6 KiB
C++

/*
* Copyright (c) 2025, RatcheT2497 <[email protected]>
* Copyright (c) 2026, Undefine <[email protected]>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <LibACPI/Definitions.h>
#include <LibACPI/OpcodeFilters.h>
#include <LibACPI/OpcodeFrame.h>
#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<OperandType, 1> EMPTY_OPERANDS = { OperandType::End };
constexpr static Array<OperandType, 3> SCOPE_OPERANDS = { OperandType::PackageLength, OperandType::NameString, OperandType::End };
constexpr static Array<OperandType, 3> NAME_OPERANDS = { OperandType::NameString, OperandType::DataRefObject, OperandType::End };
constexpr static Array<OperandType, 2> BYTE_CONST_OPERANDS = { OperandType::ByteData, OperandType::End };
constexpr static Array<OperandType, 2> WORD_CONST_OPERANDS = { OperandType::WordData, OperandType::End };
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, 4> METHOD_OPERANDS = {
OperandType::PackageLength,
OperandType::NameString,
OperandType::ByteData,
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) {
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> OpcodeFrame::from_opcode(Opcode opcode, size_t start)
{
auto operand_template = TRY(get_opcode_operand_template(opcode));
return OpcodeFrame(opcode, TRY(Vector<OperandType>::from_span(operand_template)), start);
}
ErrorOr<OpcodeFrame> OpcodeFrame::root_frame()
{
return OpcodeFrame({}, TRY(Vector<OperandType>::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<OperandType> 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<u64>());
check_repeat_opcodes(current_offset);
}
}
return peek_next_operand();
}
ErrorOr<void> 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<void> 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;
}
}