mirror of
https://github.com/SerenityOS/serenity.git
synced 2026-11-07 04:29:30 -10:00
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]>
183 lines
5.4 KiB
C++
183 lines
5.4 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, 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::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;
|
|
}
|
|
|
|
}
|