#pragma once #include #include #include #include #include #include namespace Kernel::ACPI::AML { struct Buffer final : public AML::Node { BAN::Vector buffer; Buffer() : AML::Node(Node::Type::Buffer) {} BAN::Optional logical_compare(BAN::RefPtr node, AML::Byte binaryop) { auto rhs_node = node ? node->convert(AML::Node::ConvBuffer) : BAN::RefPtr(); if (!rhs_node) { AML_ERROR("Buffer logical compare RHS cannot be converted to buffer"); return {}; } (void)binaryop; AML_TODO("Logical compare buffer"); return {}; } BAN::RefPtr convert(uint8_t mask) override { if (mask & AML::Node::ConvBuffer) return this; if (mask & AML::Node::ConvInteger) return as_integer(); if (mask & AML::Node::ConvString) { AML_TODO("Convert BufferField to String"); return {}; } return {}; } static ParseResult parse(AML::ParseContext& context) { ASSERT(context.aml_data.size() >= 1); ASSERT(static_cast(context.aml_data[0]) == Byte::BufferOp); context.aml_data = context.aml_data.slice(1); auto buffer_pkg = AML::parse_pkg(context.aml_data); if (!buffer_pkg.has_value()) return ParseResult::Failure; auto buffer_context = context; buffer_context.aml_data = buffer_pkg.value(); auto buffer_size_result = AML::parse_object(buffer_context); if (!buffer_size_result.success()) return ParseResult::Failure; auto buffer_size_node = buffer_size_result.node() ? buffer_size_result.node()->convert(AML::Node::ConvInteger) : BAN::RefPtr(); if (!buffer_size_node) { AML_ERROR("Buffer size is not an integer"); return ParseResult::Failure; } const uint32_t actual_buffer_size = BAN::Math::max( static_cast(buffer_size_node.ptr())->value, buffer_context.aml_data.size() ); auto buffer = MUST(BAN::RefPtr::create()); MUST(buffer->buffer.resize(actual_buffer_size, 0)); for (uint32_t i = 0; i < buffer_context.aml_data.size(); i++) buffer->buffer[i] = buffer_context.aml_data[i]; #if AML_DEBUG_LEVEL >= 2 buffer->debug_print(0); AML_DEBUG_PRINTLN(""); #endif return ParseResult(buffer); } virtual void debug_print(int indent) const override { AML_DEBUG_PRINT_INDENT(indent); AML_DEBUG_PRINT("Buffer ({} bytes)", buffer.size()); } private: BAN::RefPtr as_integer() { uint64_t value = 0; for (size_t i = 0; i < BAN::Math::min(buffer.size(), 8); i++) value |= static_cast(buffer[i]) << (8 * i); return MUST(BAN::RefPtr::create(value)); } }; struct BufferField final : AML::NamedObject { BAN::RefPtr buffer; size_t field_bit_offset; size_t field_bit_size; template requires BAN::is_same_v || BAN::is_same_v BufferField(AML::NameSeg name, BAN::RefPtr buffer, size_t field_bit_offset, size_t field_bit_size) : AML::NamedObject(Node::Type::BufferField, name) , buffer(buffer) , field_bit_offset(field_bit_offset) , field_bit_size(field_bit_size) {} BAN::RefPtr convert(uint8_t mask) override { if (mask & AML::Node::ConvBufferField) return this; if (mask & AML::Node::ConvInteger) return as_integer(); if (mask & AML::Node::ConvBuffer) { AML_TODO("Convert BufferField to Buffer"); return {}; } if (mask & AML::Node::ConvString) { AML_TODO("Convert BufferField to String"); return {}; } return {}; } BAN::RefPtr store(BAN::RefPtr node) override { ASSERT(buffer); ASSERT(buffer->type == AML::Node::Type::Buffer || buffer->type == AML::Node::Type::String); auto& buffer = (this->buffer->type == AML::Node::Type::Buffer) ? static_cast(this->buffer.ptr())->buffer : static_cast(this->buffer.ptr())->string; ASSERT(field_bit_offset + field_bit_size <= buffer.size() * 8); auto value_node = node ? node->convert(AML::Node::ConvInteger) : BAN::RefPtr(); if (!value_node) return {}; const auto value = static_cast(value_node.ptr())->value; // TODO: optimize for whole byte accesses for (size_t i = 0; i < field_bit_size; i++) { const size_t bit = field_bit_offset + 1; buffer[bit / 8] &= ~(1 << (bit % 8)); buffer[bit / 8] |= ((value >> i) & 1) << (bit % 8); } return value_node; } static ParseResult parse(AML::ParseContext& context) { ASSERT(context.aml_data.size() >= 1); size_t field_bit_size = 0; switch (static_cast(context.aml_data[0])) { case AML::Byte::CreateBitFieldOp: field_bit_size = 1; break; case AML::Byte::CreateByteFieldOp: field_bit_size = 8; break; case AML::Byte::CreateWordFieldOp: field_bit_size = 16; break; case AML::Byte::CreateDWordFieldOp: field_bit_size = 32; break; case AML::Byte::CreateQWordFieldOp: field_bit_size = 64; break; case AML::Byte::ExtOpPrefix: ASSERT(context.aml_data.size() >= 2); ASSERT(static_cast(context.aml_data[1]) == AML::ExtOp::CreateFieldOp); break; default: ASSERT_NOT_REACHED(); } context.aml_data = context.aml_data.slice(1 + (static_cast(context.aml_data[0]) == AML::Byte::ExtOpPrefix)); auto buffer_result = AML::parse_object(context); if (!buffer_result.success()) return ParseResult::Failure; auto buffer_node = buffer_result.node() ? buffer_result.node()->convert(AML::Node::ConvBuffer) : BAN::RefPtr(); if (!buffer_node || buffer_node->type != Node::Type::Buffer) { AML_ERROR("Buffer source does not evaluate to a Buffer"); return ParseResult::Failure; } auto buffer = BAN::RefPtr(static_cast(buffer_node.ptr())); auto index_result = AML::parse_object(context); if (!index_result.success()) return ParseResult::Failure; auto index_node = index_result.node() ? index_result.node()->convert(AML::Node::ConvInteger) : BAN::RefPtr(); if (!index_node) { AML_ERROR("Failed to parse index for BufferField"); return ParseResult::Failure; } if (field_bit_size == 0) { auto bit_count_result = AML::parse_object(context); if (!bit_count_result.success()) return ParseResult::Failure; auto bit_count_node = bit_count_result.node() ? bit_count_result.node()->convert(AML::Node::ConvInteger) : BAN::RefPtr(); if (!bit_count_node) { AML_ERROR("Failed to parse bit count for BufferField"); return ParseResult::Failure; } field_bit_size = static_cast(bit_count_node.ptr())->value; } auto field_name = AML::NameString::parse(context.aml_data); if (!field_name.has_value()) return ParseResult::Failure; if (field_name->path.empty()) { AML_ERROR("Empty field name for BufferField"); return ParseResult::Failure; } size_t field_bit_offset = static_cast(index_node.ptr())->value; if (field_bit_size != 1) field_bit_offset *= 8; auto field = MUST(BAN::RefPtr::create(field_name->path.back(), buffer, field_bit_offset, field_bit_size)); if (!Namespace::root_namespace()->add_named_object(context, field_name.value(), field)) return ParseResult::Success; #if AML_DEBUG_LEVEL >= 2 field->debug_print(0); AML_DEBUG_PRINTLN(""); #endif return ParseResult::Success; } virtual void debug_print(int indent) const override { AML_DEBUG_PRINT_INDENT(indent); AML_DEBUG_PRINT("BufferField {} at bit offset {} ({} bits) to { ", name, field_bit_offset, field_bit_size); buffer->debug_print(0); AML_DEBUG_PRINT(" }"); } private: BAN::RefPtr as_integer() { ASSERT(buffer); ASSERT(buffer->type == AML::Node::Type::Buffer || buffer->type == AML::Node::Type::String); const auto& buffer = (this->buffer->type == AML::Node::Type::Buffer) ? static_cast(this->buffer.ptr())->buffer : static_cast(this->buffer.ptr())->string; uint64_t value = 0; // TODO: optimize for whole byte accesses for (size_t i = 0; i < BAN::Math::min(field_bit_size, 64); i++) { const size_t bit = field_bit_offset + i; value |= static_cast((buffer[bit / 8] >> (bit % 8)) & 1) << i; } return MUST(BAN::RefPtr::create(value)); } }; }