Compare commits
	
		
			18 Commits
		
	
	
		
			b6587b32b9
			...
			aefb33efff
		
	
	| Author | SHA1 | Date | 
|---|---|---|
|  | aefb33efff | |
|  | da0c45b7ee | |
|  | 956335e844 | |
|  | 701fc600cd | |
|  | e38b2cff4f | |
|  | b268293402 | |
|  | 45b9dc8be9 | |
|  | 0ad7025a17 | |
|  | 49b7467840 | |
|  | a40ef610a2 | |
|  | f9943b60e4 | |
|  | f97fb1b35d | |
|  | b959181afd | |
|  | cbc27a94ac | |
|  | 6a4f999b88 | |
|  | 7707e01352 | |
|  | e667326df5 | |
|  | f1b2d7530d | 
|  | @ -84,17 +84,18 @@ namespace Kernel::ACPI::AML | |||
| 			ASSERT(field_bit_offset + field_bit_size <= buffer->buffer.size() * 8); | ||||
| 
 | ||||
| 			uint64_t value = 0; | ||||
| 
 | ||||
| 			const size_t byte_offset = field_bit_offset / 8; | ||||
| 			const size_t bit_offset = field_bit_offset % 8; | ||||
| 			if (field_bit_size == 1) | ||||
| 			{ | ||||
| 				size_t byte_offset = field_bit_offset / 8; | ||||
| 				size_t bit_offset = field_bit_offset % 8; | ||||
| 				value = (buffer->buffer[byte_offset] >> bit_offset) & 1; | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 				ASSERT(field_bit_size % 8 == 0); | ||||
| 				ASSERT(bit_offset == 0); | ||||
| 				for (size_t byte = 0; byte < field_bit_size / 8; byte++) | ||||
| 					value |= buffer->buffer[byte] << byte; | ||||
| 					value |= buffer->buffer[byte_offset + byte] << byte; | ||||
| 			} | ||||
| 
 | ||||
| 			return MUST(BAN::RefPtr<AML::Integer>::create(value)); | ||||
|  | @ -109,18 +110,18 @@ namespace Kernel::ACPI::AML | |||
| 			if (!value.has_value()) | ||||
| 				return false; | ||||
| 
 | ||||
| 			const size_t byte_offset = field_bit_offset / 8; | ||||
| 			const size_t bit_offset = field_bit_offset % 8; | ||||
| 			if (field_bit_size == 1) | ||||
| 			{ | ||||
| 				size_t byte_offset = field_bit_offset / 8; | ||||
| 				size_t bit_offset = field_bit_offset % 8; | ||||
| 				buffer->buffer[byte_offset] &= ~(1 << bit_offset); | ||||
| 				buffer->buffer[byte_offset] |= (value.value() & 1) << bit_offset; | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 				ASSERT(field_bit_size % 8 == 0); | ||||
| 				ASSERT(bit_offset == 0); | ||||
| 				for (size_t byte = 0; byte < field_bit_size / 8; byte++) | ||||
| 					buffer->buffer[byte] = (value.value() >> (byte * 8)) & 0xFF; | ||||
| 					buffer->buffer[byte_offset + byte] = (value.value() >> (byte * 8)) & 0xFF; | ||||
| 			} | ||||
| 
 | ||||
| 			return true; | ||||
|  |  | |||
|  | @ -42,11 +42,13 @@ namespace Kernel::ACPI::AML | |||
| 			AML_DEBUG_PRINT("Device "); | ||||
| 			name.debug_print(); | ||||
| 			AML_DEBUG_PRINTLN(" {"); | ||||
| 			for (const auto& [name, object] : objects) | ||||
| 			Namespace::root_namespace()->for_each_child(scope, | ||||
| 				[&](const auto&, const auto& child) | ||||
| 				{ | ||||
| 				object->debug_print(indent + 1); | ||||
| 					child->debug_print(indent + 1); | ||||
| 					AML_DEBUG_PRINTLN(""); | ||||
| 				} | ||||
| 			); | ||||
| 			AML_DEBUG_PRINT_INDENT(indent); | ||||
| 			AML_DEBUG_PRINT("}"); | ||||
| 		} | ||||
|  |  | |||
|  | @ -104,6 +104,7 @@ namespace Kernel::ACPI::AML | |||
| 				AML_ERROR("BinaryOP {2H} LHS not an integer", static_cast<uint8_t>(opcode)); | ||||
| 				if (lhs_result.node()) | ||||
| 					lhs_result.node()->debug_print(1); | ||||
| 				AML_DEBUG_PRINTLN(""); | ||||
| 				return ParseResult::Failure; | ||||
| 			} | ||||
| 
 | ||||
|  | @ -116,6 +117,7 @@ namespace Kernel::ACPI::AML | |||
| 				AML_ERROR("BinaryOP {2H} RHS not an integer", static_cast<uint8_t>(opcode)); | ||||
| 				if (rhs_result.node()) | ||||
| 					rhs_result.node()->debug_print(1); | ||||
| 				AML_DEBUG_PRINTLN(""); | ||||
| 				return ParseResult::Failure; | ||||
| 			} | ||||
| 
 | ||||
|  |  | |||
|  | @ -73,6 +73,7 @@ namespace Kernel::ACPI::AML | |||
| 		bool store_internal(uint64_t value); | ||||
| 
 | ||||
| 		friend struct IndexFieldElement; | ||||
| 		friend struct BankFieldElement; | ||||
| 	}; | ||||
| 
 | ||||
| 	struct Field | ||||
|  | @ -116,7 +117,7 @@ namespace Kernel::ACPI::AML | |||
| 		FieldRules access_rules; | ||||
| 
 | ||||
| 		BAN::RefPtr<OpRegion> op_region; | ||||
| 		BAN::RefPtr<NamedObject> bank_selector; | ||||
| 		BAN::RefPtr<FieldElement> bank_selector; | ||||
| 		uint64_t bank_value; | ||||
| 
 | ||||
| 		BankFieldElement(NameSeg name, uint64_t bit_offset, uint64_t bit_count, FieldRules access_rules) | ||||
|  | @ -126,6 +127,9 @@ namespace Kernel::ACPI::AML | |||
| 			, access_rules(access_rules) | ||||
| 		{} | ||||
| 
 | ||||
| 		BAN::RefPtr<Node> evaluate() override; | ||||
| 		bool store(BAN::RefPtr<Node> source) override; | ||||
| 
 | ||||
| 		void debug_print(int indent) const override; | ||||
| 	}; | ||||
| 
 | ||||
|  |  | |||
|  | @ -23,36 +23,28 @@ namespace Kernel::ACPI::AML | |||
| 			auto outer_aml_data = context.aml_data; | ||||
| 			context.aml_data = if_pkg.value(); | ||||
| 
 | ||||
| 			auto predicate = AML::parse_object(context); | ||||
| 			if (!predicate.success()) | ||||
| 			auto predicate_result = AML::parse_object(context); | ||||
| 			if (!predicate_result.success()) | ||||
| 				return ParseResult::Failure; | ||||
| 			auto predicate_node = predicate.node(); | ||||
| 			if (!predicate_node) | ||||
| 			{ | ||||
| 				AML_ERROR("If predicate is not an integer"); | ||||
| 				return ParseResult::Failure; | ||||
| 			} | ||||
| 			auto predicate_integer = predicate_node->as_integer(); | ||||
| 			if (!predicate_integer.has_value()) | ||||
| 			auto predicate = predicate_result.node() ? predicate_result.node()->as_integer() : BAN::Optional<uint64_t>(); | ||||
| 			if (!predicate.has_value()) | ||||
| 			{ | ||||
| 				AML_ERROR("If predicate is not an integer"); | ||||
| 				return ParseResult::Failure; | ||||
| 			} | ||||
| 
 | ||||
| 			// Else
 | ||||
| 			if (!predicate_integer.value()) | ||||
| 			{ | ||||
| 				if (outer_aml_data.size() < 1 || static_cast<Byte>(outer_aml_data[0]) != Byte::ElseOp) | ||||
| 					context.aml_data = BAN::ConstByteSpan(); | ||||
| 				else | ||||
| 			BAN::ConstByteSpan else_pkg; | ||||
| 			if (outer_aml_data.size() >= 1 && static_cast<AML::Byte>(outer_aml_data[0]) == Byte::ElseOp) | ||||
| 			{ | ||||
| 				outer_aml_data = outer_aml_data.slice(1); | ||||
| 					auto else_pkg = AML::parse_pkg(outer_aml_data); | ||||
| 					if (!else_pkg.has_value()) | ||||
| 				auto else_pkg_result = AML::parse_pkg(outer_aml_data); | ||||
| 				if (!else_pkg_result.has_value()) | ||||
| 					return ParseResult::Failure; | ||||
| 					context.aml_data = else_pkg.value(); | ||||
| 				} | ||||
| 				else_pkg = else_pkg_result.value(); | ||||
| 			} | ||||
| 			if (!predicate.value()) | ||||
| 				context.aml_data = else_pkg; | ||||
| 
 | ||||
| 			while (context.aml_data.size() > 0) | ||||
| 			{ | ||||
|  |  | |||
|  | @ -1,5 +1,6 @@ | |||
| #pragma once | ||||
| 
 | ||||
| #include <BAN/Function.h> | ||||
| #include <kernel/ACPI/AML/Bytes.h> | ||||
| #include <kernel/ACPI/AML/Namespace.h> | ||||
| #include <kernel/ACPI/AML/ParseContext.h> | ||||
|  | @ -11,13 +12,12 @@ namespace Kernel::ACPI::AML | |||
| 
 | ||||
| 	struct Method : public AML::Scope | ||||
| 	{ | ||||
| 		using Arguments = BAN::Array<BAN::RefPtr<AML::Register>, 7>; | ||||
| 
 | ||||
| 		Mutex mutex; | ||||
| 		Kernel::Mutex mutex; | ||||
| 		uint8_t arg_count; | ||||
| 		bool serialized; | ||||
| 		uint8_t sync_level; | ||||
| 
 | ||||
| 		BAN::Function<BAN::RefPtr<AML::Node>(ParseContext&)> override_function; | ||||
| 		BAN::ConstByteSpan term_list; | ||||
| 
 | ||||
| 		Method(AML::NameSeg name, uint8_t arg_count, bool serialized, uint8_t sync_level) | ||||
|  | @ -54,12 +54,7 @@ namespace Kernel::ACPI::AML | |||
| 			)); | ||||
| 			if (!Namespace::root_namespace()->add_named_object(context, name_string.value(), method)) | ||||
| 				return ParseResult::Failure; | ||||
| 
 | ||||
| 			auto method_scope = Namespace::root_namespace()->resolve_path(context.scope, name_string.value()); | ||||
| 			if (!method_scope.has_value()) | ||||
| 				return ParseResult::Failure; | ||||
| 			method->term_list = method_pkg.value(); | ||||
| 			method->scope = method_scope.release_value(); | ||||
| 
 | ||||
| #if AML_DEBUG_LEVEL >= 2 | ||||
| 			method->debug_print(0); | ||||
|  | @ -69,7 +64,30 @@ namespace Kernel::ACPI::AML | |||
| 			return ParseResult::Success; | ||||
| 		} | ||||
| 
 | ||||
| 		BAN::Optional<BAN::RefPtr<AML::Node>> evaluate(Arguments args, BAN::Vector<uint8_t>& current_sync_stack) | ||||
| 		BAN::Optional<BAN::RefPtr<AML::Node>> invoke( | ||||
| 			BAN::RefPtr<AML::Node> arg0 = {}, | ||||
| 			BAN::RefPtr<AML::Node> arg1 = {}, | ||||
| 			BAN::RefPtr<AML::Node> arg2 = {}, | ||||
| 			BAN::RefPtr<AML::Node> arg3 = {}, | ||||
| 			BAN::RefPtr<AML::Node> arg4 = {}, | ||||
| 			BAN::RefPtr<AML::Node> arg5 = {}, | ||||
| 			BAN::RefPtr<AML::Node> arg6 = {} | ||||
| 		) | ||||
| 		{ | ||||
| 			BAN::Vector<uint8_t> sync_stack; | ||||
| 			return invoke_with_sync_stack(sync_stack, arg0, arg1, arg2, arg3, arg4, arg5, arg6); | ||||
| 		} | ||||
| 
 | ||||
| 		BAN::Optional<BAN::RefPtr<AML::Node>> invoke_with_sync_stack( | ||||
| 			BAN::Vector<uint8_t>& current_sync_stack, | ||||
| 			BAN::RefPtr<AML::Node> arg0 = {}, | ||||
| 			BAN::RefPtr<AML::Node> arg1 = {}, | ||||
| 			BAN::RefPtr<AML::Node> arg2 = {}, | ||||
| 			BAN::RefPtr<AML::Node> arg3 = {}, | ||||
| 			BAN::RefPtr<AML::Node> arg4 = {}, | ||||
| 			BAN::RefPtr<AML::Node> arg5 = {}, | ||||
| 			BAN::RefPtr<AML::Node> arg6 = {} | ||||
| 		) | ||||
| 		{ | ||||
| 			if (serialized && !current_sync_stack.empty() && sync_level < current_sync_stack.back()) | ||||
| 			{ | ||||
|  | @ -80,7 +98,13 @@ namespace Kernel::ACPI::AML | |||
| 			ParseContext context; | ||||
| 			context.aml_data = term_list; | ||||
| 			context.scope = scope; | ||||
| 			context.method_args = args; | ||||
| 			context.method_args[0] = MUST(BAN::RefPtr<AML::Register>::create(arg0)); | ||||
| 			context.method_args[1] = MUST(BAN::RefPtr<AML::Register>::create(arg1)); | ||||
| 			context.method_args[2] = MUST(BAN::RefPtr<AML::Register>::create(arg2)); | ||||
| 			context.method_args[3] = MUST(BAN::RefPtr<AML::Register>::create(arg3)); | ||||
| 			context.method_args[4] = MUST(BAN::RefPtr<AML::Register>::create(arg4)); | ||||
| 			context.method_args[5] = MUST(BAN::RefPtr<AML::Register>::create(arg5)); | ||||
| 			context.method_args[6] = MUST(BAN::RefPtr<AML::Register>::create(arg6)); | ||||
| 			context.sync_stack = BAN::move(current_sync_stack); | ||||
| 			for (auto& local : context.method_locals) | ||||
| 				local = MUST(BAN::RefPtr<AML::Register>::create()); | ||||
|  | @ -95,8 +119,12 @@ namespace Kernel::ACPI::AML | |||
| 			AML_DEBUG_PRINTLN("Evaluating {}", scope); | ||||
| #endif | ||||
| 
 | ||||
| 
 | ||||
| 			BAN::Optional<BAN::RefPtr<AML::Node>> return_value = BAN::RefPtr<AML::Node>(); | ||||
| 
 | ||||
| 			if (override_function) | ||||
| 				return_value = override_function(context); | ||||
| 			else | ||||
| 			{ | ||||
| 				while (context.aml_data.size() > 0) | ||||
| 				{ | ||||
| 					auto parse_result = AML::parse_object(context); | ||||
|  | @ -112,6 +140,7 @@ namespace Kernel::ACPI::AML | |||
| 						break; | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 
 | ||||
| 			while (!context.created_objects.empty()) | ||||
| 			{ | ||||
|  |  | |||
|  | @ -36,6 +36,14 @@ namespace Kernel::ACPI::AML | |||
| 			aml_data = aml_data.slice(4); | ||||
| 		} | ||||
| 
 | ||||
| 		BAN::StringView sv() const | ||||
| 		{ | ||||
| 			size_t len = 4; | ||||
| 			while (len > 0 && chars[len - 1] == '_') | ||||
| 				len--; | ||||
| 			return BAN::StringView(chars, len); | ||||
| 		} | ||||
| 
 | ||||
| 		static BAN::Optional<NameSeg> parse(BAN::ConstByteSpan& aml_data) | ||||
| 		{ | ||||
| 			if (aml_data.size() < 4) | ||||
|  |  | |||
|  | @ -1,5 +1,6 @@ | |||
| #pragma once | ||||
| 
 | ||||
| #include <BAN/HashMap.h> | ||||
| #include <kernel/ACPI/AML/Scope.h> | ||||
| #include <kernel/ACPI/Headers.h> | ||||
| #include <kernel/Lock/Mutex.h> | ||||
|  | @ -11,21 +12,52 @@ namespace Kernel::ACPI::AML | |||
| 	{ | ||||
| 		static BAN::RefPtr<AML::Namespace> root_namespace(); | ||||
| 
 | ||||
| 		template<typename F> | ||||
| 		static void for_each_child(const AML::NameString& scope, const F& callback) | ||||
| 		{ | ||||
| 			auto canonical_path = root_namespace()->resolve_path(scope, {}, FindMode::ForceAbsolute); | ||||
| 			ASSERT(canonical_path.has_value()); | ||||
| 
 | ||||
| 			for (auto& [path, child] : root_namespace()->m_objects) | ||||
| 			{ | ||||
| 				if (path.size() < canonical_path->size() + 1) | ||||
| 					continue; | ||||
| 				if (canonical_path->size() != 1 && path[canonical_path->size()] != '.') | ||||
| 					continue; | ||||
| 				if (path.sv().substring(0, canonical_path->size()) != canonical_path->sv()) | ||||
| 					continue; | ||||
| 				if (path.sv().substring(canonical_path->size() + 1).contains('.')) | ||||
| 					continue; | ||||
| 				callback(path, child); | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		Namespace(NameSeg name) : AML::Scope(Node::Type::Namespace, name) {} | ||||
| 
 | ||||
| 		static BAN::RefPtr<AML::Namespace> create_root_namespace(); | ||||
| 		bool parse(const SDTHeader& header); | ||||
| 
 | ||||
| 		BAN::Optional<AML::NameString> resolve_path(const AML::NameString& relative_base, const AML::NameString& relative_path); | ||||
| 		void debug_print(int indent) const override; | ||||
| 
 | ||||
| 		enum class FindMode | ||||
| 		{ | ||||
| 			Normal, | ||||
| 			ForceAbsolute, | ||||
| 		}; | ||||
| 		BAN::Optional<BAN::String> resolve_path(const AML::NameString& relative_base, const AML::NameString& relative_path, FindMode mode, bool check_existence = true) const; | ||||
| 
 | ||||
| 		// Find an object in the namespace. Returns nullptr if the object is not found.
 | ||||
| 		BAN::RefPtr<NamedObject> find_object(const AML::NameString& relative_base, const AML::NameString& relative_path); | ||||
| 		BAN::RefPtr<NamedObject> find_object(const AML::NameString& relative_base, const AML::NameString& relative_path, FindMode mode); | ||||
| 
 | ||||
| 		// Add an object to the namespace. Returns false if the parent object could not be added.
 | ||||
| 		bool add_named_object(ParseContext&, const AML::NameString& object_path, BAN::RefPtr<NamedObject> object); | ||||
| 
 | ||||
| 		// Remove an object from the namespace. Returns false if the object could not be removed.
 | ||||
| 		bool remove_named_object(const AML::NameString& absolute_path); | ||||
| 
 | ||||
| 	private: | ||||
| 		BAN::HashMap<BAN::String, BAN::RefPtr<NamedObject>> m_objects; | ||||
| 		mutable Mutex m_object_mutex; | ||||
| 	}; | ||||
| 
 | ||||
| } | ||||
|  |  | |||
|  | @ -0,0 +1,66 @@ | |||
| #pragma once | ||||
| 
 | ||||
| #include <kernel/ACPI/AML/Device.h> | ||||
| #include <kernel/ACPI/AML/ParseContext.h> | ||||
| #include <kernel/ACPI/AML/Processor.h> | ||||
| #include <kernel/ACPI/AML/ThermalZone.h> | ||||
| 
 | ||||
| namespace Kernel::ACPI::AML | ||||
| { | ||||
| 
 | ||||
| 	struct Notify | ||||
| 	{ | ||||
| 		static ParseResult parse(ParseContext& context) | ||||
| 		{ | ||||
| 			ASSERT(context.aml_data.size() >= 1); | ||||
| 			ASSERT(static_cast<Byte>(context.aml_data[0]) == Byte::NotifyOp); | ||||
| 			context.aml_data = context.aml_data.slice(1); | ||||
| 
 | ||||
| 			auto object_result = AML::parse_object(context); | ||||
| 			if (!object_result.success()) | ||||
| 				return ParseResult::Failure; | ||||
| 			auto object = object_result.node(); | ||||
| 			if (!object) | ||||
| 			{ | ||||
| 				AML_ERROR("Notify object is null"); | ||||
| 				return ParseResult::Failure; | ||||
| 			} | ||||
| 
 | ||||
| 			auto value_result = AML::parse_object(context); | ||||
| 			if (!value_result.success()) | ||||
| 				return ParseResult::Failure; | ||||
| 			auto value = value_result.node() ? value_result.node()->as_integer() : BAN::Optional<uint64_t>(); | ||||
| 			if (!value.has_value()) | ||||
| 			{ | ||||
| 				AML_ERROR("Notify value is not an integer"); | ||||
| 				return ParseResult::Failure; | ||||
| 			} | ||||
| 
 | ||||
| 			BAN::StringView object_type_sv; | ||||
| 			BAN::StringView object_name_sv; | ||||
| 			switch (object->type) | ||||
| 			{ | ||||
| 				case AML::Node::Type::Device: | ||||
| 					object_type_sv = "Device"sv; | ||||
| 					object_name_sv = static_cast<AML::Device*>(object.ptr())->name.sv(); | ||||
| 					break; | ||||
| 				case AML::Node::Type::Processor: | ||||
| 					object_type_sv = "Processor"sv; | ||||
| 					object_name_sv = static_cast<AML::Processor*>(object.ptr())->name.sv(); | ||||
| 					break; | ||||
| 				case AML::Node::Type::ThermalZone: | ||||
| 					object_type_sv = "ThermalZone"sv; | ||||
| 					object_name_sv = static_cast<AML::ThermalZone*>(object.ptr())->name.sv(); | ||||
| 					break; | ||||
| 				default: | ||||
| 					object_type_sv = "Unknown"sv; | ||||
| 					object_name_sv = "????"sv; | ||||
| 					break; | ||||
| 			} | ||||
| 
 | ||||
| 			AML_TODO("Notify: {} {}: {2H}", object_type_sv, object_name_sv, value.value()); | ||||
| 			return ParseResult::Success; | ||||
| 		} | ||||
| 	}; | ||||
| 
 | ||||
| } | ||||
|  | @ -32,7 +32,7 @@ namespace Kernel::ACPI::AML | |||
| 			// resolve references
 | ||||
| 			for (auto& reference : unresolved_references) | ||||
| 			{ | ||||
| 				auto object = Namespace::root_namespace()->find_object(scope, reference.name); | ||||
| 				auto object = Namespace::root_namespace()->find_object(scope, reference.name, Namespace::FindMode::Normal); | ||||
| 				if (!object) | ||||
| 				{ | ||||
| 					AML_ERROR("Failed to resolve reference {} in package", reference.name); | ||||
|  | @ -102,11 +102,13 @@ namespace Kernel::ACPI::AML | |||
| 			AML_DEBUG_PRINTLN(""); | ||||
| 			for (const auto& element : elements) | ||||
| 			{ | ||||
| 				AML_DEBUG_PRINT_INDENT(indent + 1); | ||||
| 				if (element) | ||||
| 					element->debug_print(0); | ||||
| 					element->debug_print(indent + 1); | ||||
| 				else | ||||
| 				{ | ||||
| 					AML_DEBUG_PRINT_INDENT(indent + 1); | ||||
| 					AML_DEBUG_PRINT("Uninitialized"); | ||||
| 				} | ||||
| 				AML_DEBUG_PRINTLN(""); | ||||
| 			} | ||||
| 			AML_DEBUG_PRINT_INDENT(indent); | ||||
|  |  | |||
|  | @ -68,7 +68,16 @@ namespace Kernel::ACPI::AML | |||
| 		virtual void debug_print(int indent) const override | ||||
| 		{ | ||||
| 			AML_DEBUG_PRINT_INDENT(indent); | ||||
| 			AML_DEBUG_PRINT("Processor {} (ID: {}, PBlkAddr: 0x{H}, PBlkLen: {})", name, id, pblk_addr, pblk_len); | ||||
| 			AML_DEBUG_PRINTLN("Processor {} (ID: {}, PBlkAddr: 0x{H}, PBlkLen: {}) {", name, id, pblk_addr, pblk_len); | ||||
| 			Namespace::root_namespace()->for_each_child(scope, | ||||
| 				[&](const auto&, const auto& child) | ||||
| 				{ | ||||
| 					child->debug_print(indent + 1); | ||||
| 					AML_DEBUG_PRINTLN(""); | ||||
| 				} | ||||
| 			); | ||||
| 			AML_DEBUG_PRINT_INDENT(indent); | ||||
| 			AML_DEBUG_PRINT("}"); | ||||
| 		} | ||||
| 	}; | ||||
| 
 | ||||
|  |  | |||
|  | @ -54,7 +54,7 @@ namespace Kernel::ACPI::AML | |||
| 				auto name = NameString::parse(context.aml_data); | ||||
| 				if (!name.has_value()) | ||||
| 					return ParseResult::Failure; | ||||
| 				object = Namespace::root_namespace()->find_object(context.scope, name.value()); | ||||
| 				object = Namespace::root_namespace()->find_object(context.scope, name.value(), Namespace::FindMode::Normal); | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
|  |  | |||
|  | @ -27,6 +27,8 @@ namespace Kernel::ACPI::AML | |||
| 		uint64_t region_offset; | ||||
| 		uint64_t region_length; | ||||
| 
 | ||||
| 		Kernel::Mutex mutex; | ||||
| 
 | ||||
| 		OpRegion(NameSeg name, RegionSpace region_space, uint64_t region_offset, uint64_t region_length) | ||||
| 			: NamedObject(Node::Type::OpRegion, name) | ||||
| 			, region_space(region_space) | ||||
|  |  | |||
|  | @ -1,6 +1,5 @@ | |||
| #pragma once | ||||
| 
 | ||||
| #include <BAN/HashMap.h> | ||||
| #include <kernel/ACPI/AML/NamedObject.h> | ||||
| #include <kernel/ACPI/AML/Names.h> | ||||
| 
 | ||||
|  | @ -9,7 +8,6 @@ namespace Kernel::ACPI::AML | |||
| 
 | ||||
| 	struct Scope : public AML::NamedObject | ||||
| 	{ | ||||
| 		BAN::HashMap<NameSeg, BAN::RefPtr<NamedObject>> objects; | ||||
| 		AML::NameString scope; | ||||
| 
 | ||||
| 		Scope(Node::Type type, NameSeg name) | ||||
|  | @ -19,7 +17,6 @@ namespace Kernel::ACPI::AML | |||
| 		virtual bool is_scope() const override { return true; } | ||||
| 
 | ||||
| 		static ParseResult parse(ParseContext& context); | ||||
| 		virtual void debug_print(int indent) const override; | ||||
| 
 | ||||
| 	protected: | ||||
| 		ParseResult enter_context_and_parse_term_list(ParseContext& outer_context, const AML::NameString& name, BAN::ConstByteSpan aml_data); | ||||
|  |  | |||
|  | @ -13,6 +13,11 @@ namespace Kernel::ACPI::AML | |||
| 
 | ||||
| 		String() : Node(Node::Type::String) {} | ||||
| 
 | ||||
| 		BAN::RefPtr<AML::Node> evaluate() override | ||||
| 		{ | ||||
| 			return this; | ||||
| 		} | ||||
| 
 | ||||
| 		static ParseResult parse(ParseContext& context) | ||||
| 		{ | ||||
| 			ASSERT(context.aml_data.size() >= 1); | ||||
|  |  | |||
|  | @ -46,7 +46,16 @@ namespace Kernel::ACPI::AML | |||
| 		virtual void debug_print(int indent) const override | ||||
| 		{ | ||||
| 			AML_DEBUG_PRINT_INDENT(indent); | ||||
| 			AML_DEBUG_PRINT("ThermalZone {}", name); | ||||
| 			AML_DEBUG_PRINT("ThermalZone {} {", name); | ||||
| 			Namespace::root_namespace()->for_each_child(scope, | ||||
| 				[&](const auto&, const auto& child) | ||||
| 				{ | ||||
| 					child->debug_print(indent + 1); | ||||
| 					AML_DEBUG_PRINTLN(""); | ||||
| 				} | ||||
| 			); | ||||
| 			AML_DEBUG_PRINT_INDENT(indent); | ||||
| 			AML_DEBUG_PRINT("}"); | ||||
| 		} | ||||
| 	}; | ||||
| 
 | ||||
|  |  | |||
|  | @ -0,0 +1,65 @@ | |||
| #pragma once | ||||
| 
 | ||||
| #include <kernel/ACPI/AML/Node.h> | ||||
| #include <kernel/ACPI/AML/ParseContext.h> | ||||
| #include <kernel/ACPI/AML/Pkg.h> | ||||
| 
 | ||||
| namespace Kernel::ACPI::AML | ||||
| { | ||||
| 
 | ||||
| 	struct While | ||||
| 	{ | ||||
| 		static ParseResult parse(ParseContext& context) | ||||
| 		{ | ||||
| 			ASSERT(context.aml_data.size() >= 1); | ||||
| 			ASSERT(static_cast<Byte>(context.aml_data[0]) == Byte::WhileOp); | ||||
| 			context.aml_data = context.aml_data.slice(1); | ||||
| 
 | ||||
| 			auto while_pkg = AML::parse_pkg(context.aml_data); | ||||
| 			if (!while_pkg.has_value()) | ||||
| 				return ParseResult::Failure; | ||||
| 
 | ||||
| 			auto outer_aml_data = context.aml_data; | ||||
| 
 | ||||
| 			bool breaked = false; | ||||
| 			while (!breaked) | ||||
| 			{ | ||||
| 				context.aml_data = while_pkg.value(); | ||||
| 
 | ||||
| 				auto predicate_result = AML::parse_object(context); | ||||
| 				if (!predicate_result.success()) | ||||
| 					return ParseResult::Failure; | ||||
| 				auto predicate = predicate_result.node() ? predicate_result.node()->as_integer() : BAN::Optional<uint64_t>(); | ||||
| 				if (!predicate.has_value()) | ||||
| 				{ | ||||
| 					AML_ERROR("While predicate is not an integer"); | ||||
| 					return ParseResult::Failure; | ||||
| 				} | ||||
| 
 | ||||
| 				if (!predicate.value()) | ||||
| 					break; | ||||
| 
 | ||||
| 				while (context.aml_data.size() > 0) | ||||
| 				{ | ||||
| 					// NOTE: we can just parse BreakOp here, since this is the only legal place for BreakOp
 | ||||
| 					if (static_cast<AML::Byte>(context.aml_data[0]) == AML::Byte::BreakOp) | ||||
| 					{ | ||||
| 						context.aml_data = context.aml_data.slice(1); | ||||
| 						breaked = true; | ||||
| 						break; | ||||
| 					} | ||||
| 					auto object_result = AML::parse_object(context); | ||||
| 					if (object_result.returned()) | ||||
| 						return ParseResult(ParseResult::Result::Returned, object_result.node()); | ||||
| 					if (!object_result.success()) | ||||
| 						return ParseResult::Failure; | ||||
| 				} | ||||
| 			} | ||||
| 
 | ||||
| 			context.aml_data = outer_aml_data; | ||||
| 
 | ||||
| 			return ParseResult::Success; | ||||
| 		} | ||||
| 	}; | ||||
| 
 | ||||
| } | ||||
|  | @ -43,6 +43,7 @@ namespace Kernel | |||
| 				ASSERT(m_lock_depth == 0); | ||||
| 			} | ||||
| 			m_lock_depth++; | ||||
| 			return true; | ||||
| 		} | ||||
| 
 | ||||
| 		void unlock() | ||||
|  |  | |||
|  | @ -61,7 +61,7 @@ namespace Kernel | |||
| 		vaddr_t kernel_stack_top() const	{ return m_kernel_stack->vaddr() + m_kernel_stack->size(); } | ||||
| 		VirtualRange& kernel_stack() { return *m_kernel_stack; } | ||||
| 
 | ||||
| 		vaddr_t userspace_stack_bottom() const	{ return is_userspace() ? m_userspace_stack->vaddr() : 0; } | ||||
| 		vaddr_t userspace_stack_bottom() const	{ return is_userspace() ? m_userspace_stack->vaddr() : UINTPTR_MAX; } | ||||
| 		vaddr_t userspace_stack_top() const		{ return is_userspace() ? m_userspace_stack->vaddr() + m_userspace_stack->size() : 0; } | ||||
| 		VirtualRange& userspace_stack() { ASSERT(is_userspace()); return *m_userspace_stack; } | ||||
| 
 | ||||
|  |  | |||
|  | @ -65,7 +65,6 @@ acpi_release_global_lock: | |||
| 	{ | ||||
| 		if (!s_global_lock) | ||||
| 			return; | ||||
| 		derrorln("Acquiring ACPI global lock"); | ||||
| 		ASSERT(acpi_acquire_global_lock(s_global_lock)); | ||||
| 	} | ||||
| 
 | ||||
|  | @ -73,7 +72,6 @@ acpi_release_global_lock: | |||
| 	{ | ||||
| 		if (!s_global_lock) | ||||
| 			return; | ||||
| 		derrorln("Releasing ACPI global lock"); | ||||
| 		ASSERT(!acpi_release_global_lock(s_global_lock)); | ||||
| 	} | ||||
| 
 | ||||
|  | @ -129,7 +127,23 @@ acpi_release_global_lock: | |||
| 
 | ||||
| 			if (facs_addr) | ||||
| 			{ | ||||
| 				auto* facs = reinterpret_cast<FACS*>(facs_addr); | ||||
| 				size_t facs_size; | ||||
| 				PageTable::with_fast_page(facs_addr & PAGE_ADDR_MASK, [&] { | ||||
| 					facs_size = PageTable::fast_page_as<SDTHeader>(facs_addr % PAGE_SIZE).length; | ||||
| 				}); | ||||
| 
 | ||||
| 				size_t needed_pages = range_page_count(facs_addr, facs_size); | ||||
| 				vaddr_t facs_vaddr = PageTable::kernel().reserve_free_contiguous_pages(needed_pages, KERNEL_OFFSET); | ||||
| 				ASSERT(facs_vaddr); | ||||
| 
 | ||||
| 				PageTable::kernel().map_range_at( | ||||
| 					facs_addr & PAGE_ADDR_MASK, | ||||
| 					facs_vaddr, | ||||
| 					needed_pages * PAGE_SIZE, | ||||
| 					PageTable::Flags::ReadWrite | PageTable::Flags::Present | ||||
| 				); | ||||
| 
 | ||||
| 				auto* facs = reinterpret_cast<FACS*>(facs_vaddr + (facs_addr % PAGE_SIZE)); | ||||
| 				s_global_lock = &facs->global_lock; | ||||
| 			} | ||||
| 		} | ||||
|  | @ -354,7 +368,7 @@ acpi_release_global_lock: | |||
| 			return; | ||||
| 		} | ||||
| 
 | ||||
| 		auto s5_object = m_namespace->find_object({}, AML::NameString("\\_S5")); | ||||
| 		auto s5_object = m_namespace->find_object({}, AML::NameString("_S5"), AML::Namespace::FindMode::ForceAbsolute); | ||||
| 		if (!s5_object) | ||||
| 		{ | ||||
| 			dwarnln("\\_S5 not found"); | ||||
|  | @ -386,7 +400,7 @@ acpi_release_global_lock: | |||
| 			return; | ||||
| 		} | ||||
| 
 | ||||
| 		auto pts_object = m_namespace->find_object({}, AML::NameString("\\_PTS")); | ||||
| 		auto pts_object = m_namespace->find_object({}, AML::NameString("_PTS"), AML::Namespace::FindMode::ForceAbsolute); | ||||
| 		if (pts_object && pts_object->type == AML::Node::Type::Method) | ||||
| 		{ | ||||
| 			auto* method = static_cast<AML::Method*>(pts_object.ptr()); | ||||
|  | @ -396,10 +410,7 @@ acpi_release_global_lock: | |||
| 				return; | ||||
| 			} | ||||
| 
 | ||||
| 			AML::Method::Arguments args; | ||||
| 			args[0] = MUST(BAN::RefPtr<AML::Register>::create(MUST(BAN::RefPtr<AML::Integer>::create(5)))); | ||||
| 			BAN::Vector<uint8_t> sync_stack; | ||||
| 			if (!method->evaluate(args, sync_stack).has_value()) | ||||
| 			if (!method->invoke(MUST(BAN::RefPtr<AML::Integer>::create(5))).has_value()) | ||||
| 			{ | ||||
| 				dwarnln("Failed to evaluate \\_PTS"); | ||||
| 				return; | ||||
|  | @ -465,7 +476,7 @@ acpi_release_global_lock: | |||
| 		dprintln("Initializing devices"); | ||||
| 
 | ||||
| 		// Initialize \\_SB
 | ||||
| 		auto _sb = m_namespace->find_object({}, AML::NameString("\\_SB")); | ||||
| 		auto _sb = m_namespace->find_object({}, AML::NameString("_SB"), AML::Namespace::FindMode::ForceAbsolute); | ||||
| 		if (_sb && _sb->is_scope()) | ||||
| 		{ | ||||
| 			auto* scope = static_cast<AML::Scope*>(_sb.ptr()); | ||||
|  | @ -473,7 +484,7 @@ acpi_release_global_lock: | |||
| 		} | ||||
| 
 | ||||
| 		// Evaluate \\_PIC (mode)
 | ||||
| 		auto _pic = m_namespace->find_object({}, AML::NameString("\\_PIC")); | ||||
| 		auto _pic = m_namespace->find_object({}, AML::NameString("_PIC"), AML::Namespace::FindMode::ForceAbsolute); | ||||
| 		if (_pic && _pic->type == AML::Node::Type::Method) | ||||
| 		{ | ||||
| 			auto* method = static_cast<AML::Method*>(_pic.ptr()); | ||||
|  | @ -482,11 +493,7 @@ acpi_release_global_lock: | |||
| 				dwarnln("Method \\_PIC has {} arguments, expected 1", method->arg_count); | ||||
| 				return BAN::Error::from_errno(EINVAL); | ||||
| 			} | ||||
| 
 | ||||
| 			AML::Method::Arguments args; | ||||
| 			args[0] = MUST(BAN::RefPtr<AML::Register>::create(MUST(BAN::RefPtr<AML::Integer>::create(mode)))); | ||||
| 			BAN::Vector<uint8_t> sync_stack; | ||||
| 			method->evaluate(args, sync_stack); | ||||
| 			method->invoke(MUST(BAN::RefPtr<AML::Integer>::create(mode))); | ||||
| 		} | ||||
| 
 | ||||
| 		dprintln("Devices are initialized"); | ||||
|  |  | |||
|  | @ -404,7 +404,7 @@ namespace Kernel::ACPI | |||
| 		if (!name_string.has_value()) | ||||
| 			return ParseResult::Failure; | ||||
| 
 | ||||
| 		auto op_region = Namespace::root_namespace()->find_object(context.scope, name_string.value()); | ||||
| 		auto op_region = Namespace::root_namespace()->find_object(context.scope, name_string.value(), Namespace::FindMode::Normal); | ||||
| 		if (!op_region || op_region->type != AML::Node::Type::OpRegion) | ||||
| 		{ | ||||
| 			AML_ERROR("FieldOp: {} does not name a valid OpRegion", name_string.value()); | ||||
|  | @ -481,6 +481,11 @@ namespace Kernel::ACPI | |||
| 
 | ||||
| 	BAN::RefPtr<AML::Node> AML::FieldElement::evaluate() | ||||
| 	{ | ||||
| 		op_region->mutex.lock(); | ||||
| 		BAN::ScopeGuard unlock_guard([&] { | ||||
| 			op_region->mutex.unlock(); | ||||
| 		}); | ||||
| 
 | ||||
| 		auto result = evaluate_internal(); | ||||
| 		if (!result.has_value()) | ||||
| 			return {}; | ||||
|  | @ -496,9 +501,11 @@ namespace Kernel::ACPI | |||
| 			return false; | ||||
| 		} | ||||
| 
 | ||||
| 		op_region->mutex.lock(); | ||||
| 		if (access_rules.lock_rule == FieldRules::LockRule::Lock) | ||||
| 			ACPI::acquire_global_lock(); | ||||
| 		BAN::ScopeGuard unlock_guard([&] { | ||||
| 			op_region->mutex.unlock(); | ||||
| 			if (access_rules.lock_rule == FieldRules::LockRule::Lock) | ||||
| 				ACPI::release_global_lock(); | ||||
| 		}); | ||||
|  | @ -532,7 +539,7 @@ namespace Kernel::ACPI | |||
| 		auto index_field_element_name = NameString::parse(field_pkg); | ||||
| 		if (!index_field_element_name.has_value()) | ||||
| 			return ParseResult::Failure; | ||||
| 		auto index_field_element = Namespace::root_namespace()->find_object(context.scope, index_field_element_name.value()); | ||||
| 		auto index_field_element = Namespace::root_namespace()->find_object(context.scope, index_field_element_name.value(), Namespace::FindMode::Normal); | ||||
| 		if (!index_field_element || index_field_element->type != AML::Node::Type::FieldElement) | ||||
| 		{ | ||||
| 			AML_ERROR("IndexField IndexName does not name a valid FieldElement"); | ||||
|  | @ -542,7 +549,7 @@ namespace Kernel::ACPI | |||
| 		auto data_field_element_name = NameString::parse(field_pkg); | ||||
| 		if (!data_field_element_name.has_value()) | ||||
| 			return ParseResult::Failure; | ||||
| 		auto data_field_element = Namespace::root_namespace()->find_object(context.scope, data_field_element_name.value()); | ||||
| 		auto data_field_element = Namespace::root_namespace()->find_object(context.scope, data_field_element_name.value(), Namespace::FindMode::Normal); | ||||
| 		if (!data_field_element || data_field_element->type != AML::Node::Type::FieldElement) | ||||
| 		{ | ||||
| 			AML_ERROR("IndexField DataName does not name a valid FieldElement"); | ||||
|  | @ -587,7 +594,7 @@ namespace Kernel::ACPI | |||
| 	{ | ||||
| 		if (access_rules.access_attrib != FieldRules::AccessAttrib::Normal) | ||||
| 		{ | ||||
| 			AML_TODO("FieldElement with access attribute {}", static_cast<uint8_t>(access_rules.access_attrib)); | ||||
| 			AML_TODO("IndexFieldElement with access attribute {}", static_cast<uint8_t>(access_rules.access_attrib)); | ||||
| 			return {}; | ||||
| 		} | ||||
| 		auto access_size = determine_access_size(access_rules.access_type); | ||||
|  | @ -604,9 +611,11 @@ namespace Kernel::ACPI | |||
| 			return data_element->evaluate_internal(); | ||||
| 		}; | ||||
| 
 | ||||
| 		index_element->op_region->mutex.lock(); | ||||
| 		if (access_rules.lock_rule == FieldRules::LockRule::Lock) | ||||
| 			ACPI::acquire_global_lock(); | ||||
| 		BAN::ScopeGuard unlock_guard([&] { | ||||
| 			index_element->op_region->mutex.unlock(); | ||||
| 			if (access_rules.lock_rule == FieldRules::LockRule::Lock) | ||||
| 				ACPI::release_global_lock(); | ||||
| 		}); | ||||
|  | @ -652,9 +661,11 @@ namespace Kernel::ACPI | |||
| 			return data_element->store_internal(value); | ||||
| 		}; | ||||
| 
 | ||||
| 		index_element->op_region->mutex.lock(); | ||||
| 		if (access_rules.lock_rule == FieldRules::LockRule::Lock) | ||||
| 			ACPI::acquire_global_lock(); | ||||
| 		BAN::ScopeGuard unlock_guard([&] { | ||||
| 			index_element->op_region->mutex.unlock(); | ||||
| 			if (access_rules.lock_rule == FieldRules::LockRule::Lock) | ||||
| 				ACPI::release_global_lock(); | ||||
| 		}); | ||||
|  | @ -694,7 +705,7 @@ namespace Kernel::ACPI | |||
| 		auto op_region_name = NameString::parse(field_pkg); | ||||
| 		if (!op_region_name.has_value()) | ||||
| 			return ParseResult::Failure; | ||||
| 		auto op_region = Namespace::root_namespace()->find_object(context.scope, op_region_name.value()); | ||||
| 		auto op_region = Namespace::root_namespace()->find_object(context.scope, op_region_name.value(), Namespace::FindMode::Normal); | ||||
| 		if (!op_region || op_region->type != AML::Node::Type::OpRegion) | ||||
| 		{ | ||||
| 			AML_ERROR("BankField RegionName {} does not name a valid OpRegion", op_region_name.value()); | ||||
|  | @ -704,12 +715,17 @@ namespace Kernel::ACPI | |||
| 		auto bank_selector_name = NameString::parse(field_pkg); | ||||
| 		if (!bank_selector_name.has_value()) | ||||
| 			return ParseResult::Failure; | ||||
| 		auto bank_selector = Namespace::root_namespace()->find_object(context.scope, bank_selector_name.value()); | ||||
| 		auto bank_selector = Namespace::root_namespace()->find_object(context.scope, bank_selector_name.value(), Namespace::FindMode::Normal); | ||||
| 		if (!bank_selector) | ||||
| 		{ | ||||
| 			AML_ERROR("BankField BankSelector {} does not name a valid object", bank_selector_name.value()); | ||||
| 			return ParseResult::Failure; | ||||
| 		} | ||||
| 		if (bank_selector->type != AML::Node::Type::FieldElement) | ||||
| 		{ | ||||
| 			AML_TODO("BankField BankSelector {} type {2H}", static_cast<uint8_t>(bank_selector->type)); | ||||
| 			return ParseResult::Failure; | ||||
| 		} | ||||
| 
 | ||||
| 		auto temp_aml_data = context.aml_data; | ||||
| 		context.aml_data = field_pkg; | ||||
|  | @ -743,7 +759,7 @@ namespace Kernel::ACPI | |||
| 		for (auto& [_, element] : field_context.elements) | ||||
| 		{ | ||||
| 			element->op_region = static_cast<OpRegion*>(op_region.ptr()); | ||||
| 			element->bank_selector = bank_selector; | ||||
| 			element->bank_selector = static_cast<FieldElement*>(bank_selector.ptr()); | ||||
| 			element->bank_value = bank_value.value(); | ||||
| 
 | ||||
| 			NameString element_name; | ||||
|  | @ -760,6 +776,85 @@ namespace Kernel::ACPI | |||
| 		return ParseResult::Success; | ||||
| 	} | ||||
| 
 | ||||
| 	BAN::RefPtr<AML::Node> AML::BankFieldElement::evaluate() | ||||
| 	{ | ||||
| 		if (access_rules.access_attrib != FieldRules::AccessAttrib::Normal) | ||||
| 		{ | ||||
| 			AML_TODO("BankFieldElement with access attribute {}", static_cast<uint8_t>(access_rules.access_attrib)); | ||||
| 			return {}; | ||||
| 		} | ||||
| 
 | ||||
| 		auto access_size = determine_access_size(access_rules.access_type); | ||||
| 		if (!access_size.has_value()) | ||||
| 			return {}; | ||||
| 		auto read_func = [&](uint64_t byte_offset) -> BAN::Optional<uint64_t> { | ||||
| 			return perform_read(op_region->region_space, byte_offset, access_size.value()); | ||||
| 		}; | ||||
| 
 | ||||
| 		bank_selector->op_region->mutex.lock(); | ||||
| 		if (access_rules.lock_rule == FieldRules::LockRule::Lock) | ||||
| 			ACPI::acquire_global_lock(); | ||||
| 		BAN::ScopeGuard unlock_guard([&] { | ||||
| 			bank_selector->op_region->mutex.unlock(); | ||||
| 			if (access_rules.lock_rule == FieldRules::LockRule::Lock) | ||||
| 				ACPI::release_global_lock(); | ||||
| 		}); | ||||
| 
 | ||||
| 		if (!bank_selector->store_internal(bank_value)) | ||||
| 		{ | ||||
| 			AML_ERROR("BankFieldElement failed to store BankValue"); | ||||
| 			return {}; | ||||
| 		} | ||||
| 
 | ||||
| 		auto result = perform_read_general(op_region->region_offset, bit_count, bit_offset, access_size.value(), read_func); | ||||
| 		if (!result.has_value()) | ||||
| 			return {}; | ||||
| 		return MUST(BAN::RefPtr<Integer>::create(result.value())); | ||||
| 	} | ||||
| 
 | ||||
| 	bool AML::BankFieldElement::store(BAN::RefPtr<AML::Node> source) | ||||
| 	{ | ||||
| 		if (access_rules.access_attrib != FieldRules::AccessAttrib::Normal) | ||||
| 		{ | ||||
| 			AML_TODO("BankFieldElement with access attribute {}", static_cast<uint8_t>(access_rules.access_attrib)); | ||||
| 			return {}; | ||||
| 		} | ||||
| 
 | ||||
| 		auto source_integer = source->as_integer(); | ||||
| 		if (!source_integer.has_value()) | ||||
| 		{ | ||||
| 			AML_TODO("BankFieldElement store with non-integer source, type {}", static_cast<uint8_t>(source->type)); | ||||
| 			return false; | ||||
| 		} | ||||
| 
 | ||||
| 		auto access_size = determine_access_size(access_rules.access_type); | ||||
| 		if (!access_size.has_value()) | ||||
| 			return false; | ||||
| 		auto read_func = [&](uint64_t byte_offset) -> BAN::Optional<uint64_t> { | ||||
| 			return perform_read(op_region->region_space, byte_offset, access_size.value()); | ||||
| 		}; | ||||
| 		auto write_func = [&](uint64_t byte_offset, uint64_t value) -> bool { | ||||
| 			return perform_write(op_region->region_space, byte_offset, access_size.value(), value); | ||||
| 		}; | ||||
| 
 | ||||
| 		bank_selector->op_region->mutex.lock(); | ||||
| 		if (access_rules.lock_rule == FieldRules::LockRule::Lock) | ||||
| 			ACPI::acquire_global_lock(); | ||||
| 		BAN::ScopeGuard unlock_guard([&] { | ||||
| 			bank_selector->op_region->mutex.unlock(); | ||||
| 			if (access_rules.lock_rule == FieldRules::LockRule::Lock) | ||||
| 				ACPI::release_global_lock(); | ||||
| 		}); | ||||
| 
 | ||||
| 		if (!bank_selector->store_internal(bank_value)) | ||||
| 		{ | ||||
| 			AML_ERROR("BankFieldElement failed to store BankValue"); | ||||
| 			return {}; | ||||
| 		} | ||||
| 
 | ||||
| 		return perform_write_general(op_region->region_offset, bit_count, bit_offset, access_size.value(), source_integer.value(), access_rules.update_rule, read_func, write_func); | ||||
| 	} | ||||
| 
 | ||||
| 	void AML::BankFieldElement::debug_print(int indent) const | ||||
| 	{ | ||||
| 		AML_DEBUG_PRINT_INDENT(indent); | ||||
|  |  | |||
|  | @ -33,8 +33,10 @@ namespace Kernel::ACPI | |||
| 	void AML::Name::debug_print(int indent) const | ||||
| 	{ | ||||
| 		AML_DEBUG_PRINT_INDENT(indent); | ||||
| 		AML_DEBUG_PRINT("Name {} { ", name); | ||||
| 		object->debug_print(0); | ||||
| 		AML_DEBUG_PRINTLN("Name {} { ", name); | ||||
| 		object->debug_print(indent + 1); | ||||
| 		AML_DEBUG_PRINTLN(""); | ||||
| 		AML_DEBUG_PRINT_INDENT(indent); | ||||
| 		AML_DEBUG_PRINT("}"); | ||||
| 	} | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,8 +1,11 @@ | |||
| #include <kernel/ACPI/AML/Device.h> | ||||
| #include <kernel/ACPI/AML/Integer.h> | ||||
| #include <kernel/ACPI/AML/Method.h> | ||||
| #include <kernel/ACPI/AML/Namespace.h> | ||||
| #include <kernel/ACPI/AML/ParseContext.h> | ||||
| #include <kernel/ACPI/AML/Region.h> | ||||
| #include <kernel/ACPI/AML/String.h> | ||||
| #include <kernel/Lock/LockGuard.h> | ||||
| 
 | ||||
| namespace Kernel::ACPI | ||||
| { | ||||
|  | @ -20,16 +23,31 @@ namespace Kernel::ACPI | |||
| 		return s_root_namespace; | ||||
| 	} | ||||
| 
 | ||||
| 	BAN::Optional<AML::NameString> AML::Namespace::resolve_path(const AML::NameString& relative_base, const AML::NameString& relative_path) | ||||
| 	void AML::Namespace::debug_print(int indent) const | ||||
| 	{ | ||||
| 		LockGuard _(m_object_mutex); | ||||
| 		AML_DEBUG_PRINT_INDENT(indent); | ||||
| 		AML_DEBUG_PRINTLN("Namespace {} {", name); | ||||
| 		for_each_child(scope, [&](const auto&, const auto& child) { | ||||
| 			child->debug_print(indent + 1); | ||||
| 			AML_DEBUG_PRINTLN(""); | ||||
| 		}); | ||||
| 		AML_DEBUG_PRINT_INDENT(indent); | ||||
| 		AML_DEBUG_PRINT("}"); | ||||
| 	} | ||||
| 
 | ||||
| 	BAN::Optional<BAN::String> AML::Namespace::resolve_path(const AML::NameString& relative_base, const AML::NameString& relative_path, FindMode mode, bool check_existence) const | ||||
| 	{ | ||||
| 		LockGuard _(m_object_mutex); | ||||
| 
 | ||||
| 		// Base must be non-empty absolute path
 | ||||
| 		ASSERT(relative_base.prefix == "\\"sv || relative_base.path.empty()); | ||||
| 
 | ||||
| 		// Do absolute path lookup
 | ||||
| 		if (!relative_path.prefix.empty() || relative_path.path.size() != 1) | ||||
| 		if (!relative_path.prefix.empty() || relative_path.path.size() != 1 || mode == FindMode::ForceAbsolute) | ||||
| 		{ | ||||
| 			AML::NameString absolute_path; | ||||
| 			MUST(absolute_path.prefix.push_back('\\')); | ||||
| 			BAN::String absolute_path; | ||||
| 			MUST(absolute_path.push_back('\\')); | ||||
| 
 | ||||
| 			// Resolve root and parent references
 | ||||
| 			if (relative_path.prefix == "\\"sv) | ||||
|  | @ -42,158 +60,130 @@ namespace Kernel::ACPI | |||
| 					return {}; | ||||
| 				} | ||||
| 				for (size_t i = 0; i < relative_base.path.size() - relative_path.prefix.size(); i++) | ||||
| 					MUST(absolute_path.path.push_back(relative_base.path[i])); | ||||
| 				{ | ||||
| 					MUST(absolute_path.append(relative_base.path[i].sv())); | ||||
| 					MUST(absolute_path.push_back('.')); | ||||
| 				} | ||||
| 			} | ||||
| 
 | ||||
| 			// Append relative path
 | ||||
| 			for (const auto& seg : relative_path.path) | ||||
| 				MUST(absolute_path.path.push_back(seg)); | ||||
| 
 | ||||
| 			// Validate path
 | ||||
| 			BAN::RefPtr<AML::NamedObject> current_node = this; | ||||
| 			for (const auto& seg : absolute_path.path) | ||||
| 			{ | ||||
| 				if (!current_node->is_scope()) | ||||
| 					return {}; | ||||
| 
 | ||||
| 				auto* current_scope = static_cast<AML::Scope*>(current_node.ptr()); | ||||
| 				auto it = current_scope->objects.find(seg); | ||||
| 				if (it == current_scope->objects.end()) | ||||
| 					return {}; | ||||
| 
 | ||||
| 				current_node = it->value; | ||||
| 				MUST(absolute_path.append(seg.sv())); | ||||
| 				MUST(absolute_path.push_back('.')); | ||||
| 			} | ||||
| 
 | ||||
| 			if (absolute_path.back() == '.') | ||||
| 				absolute_path.pop_back(); | ||||
| 
 | ||||
| 			if (!check_existence || absolute_path == "\\"sv || m_objects.contains(absolute_path)) | ||||
| 				return absolute_path; | ||||
| 			return {}; | ||||
| 		} | ||||
| 
 | ||||
| 
 | ||||
| 		// Resolve with namespace search rules (ACPI Spec 6.4 - Section 5.3)
 | ||||
| 
 | ||||
| 		AML::NameString last_match_path; | ||||
| 		AML::NameSeg target_seg = relative_path.path.back(); | ||||
| 
 | ||||
| 		BAN::RefPtr<AML::Scope> current_scope = this; | ||||
| 		AML::NameString current_path; | ||||
| 		BAN::String last_match_path; | ||||
| 		BAN::String current_path; | ||||
| 		MUST(current_path.push_back('\\')); | ||||
| 
 | ||||
| 		// Check root namespace
 | ||||
| 		{ | ||||
| 			// If scope contains object with the same name as the segment, update last match
 | ||||
| 			if (current_scope->objects.contains(target_seg)) | ||||
| 			{ | ||||
| 				last_match_path = current_path; | ||||
| 				MUST(last_match_path.path.push_back(target_seg)); | ||||
| 			} | ||||
| 			BAN::String tmp; | ||||
| 			MUST(tmp.append(current_path)); | ||||
| 			MUST(tmp.append(target_seg.sv())); | ||||
| 			if (m_objects.contains(tmp)) | ||||
| 				last_match_path = BAN::move(tmp); | ||||
| 		} | ||||
| 
 | ||||
| 		// Check base base path
 | ||||
| 		for (const auto& seg : relative_base.path) | ||||
| 		{ | ||||
| 			auto next_node = current_scope->objects[seg]; | ||||
| 			ASSERT(next_node && next_node->is_scope()); | ||||
| 			MUST(current_path.append(seg.sv())); | ||||
| 			MUST(current_path.push_back('.')); | ||||
| 
 | ||||
| 			current_scope = static_cast<AML::Scope*>(next_node.ptr()); | ||||
| 			MUST(current_path.path.push_back(seg)); | ||||
| 
 | ||||
| 			// If scope contains object with the same name as the segment, update last match
 | ||||
| 			if (current_scope->objects.contains(target_seg)) | ||||
| 			{ | ||||
| 				last_match_path = current_path; | ||||
| 				MUST(last_match_path.path.push_back(target_seg)); | ||||
| 			} | ||||
| 			BAN::String tmp; | ||||
| 			MUST(tmp.append(current_path)); | ||||
| 			MUST(tmp.append(target_seg.sv())); | ||||
| 			if (m_objects.contains(tmp)) | ||||
| 				last_match_path = BAN::move(tmp); | ||||
| 		} | ||||
| 
 | ||||
| 		if (!last_match_path.path.empty()) | ||||
| 		{ | ||||
| 			MUST(last_match_path.prefix.push_back('\\')); | ||||
| 		if (!last_match_path.empty()) | ||||
| 			return last_match_path; | ||||
| 		} | ||||
| 
 | ||||
| 		return {}; | ||||
| 	} | ||||
| 
 | ||||
| 	BAN::RefPtr<AML::NamedObject> AML::Namespace::find_object(const AML::NameString& relative_base, const AML::NameString& relative_path) | ||||
| 	BAN::RefPtr<AML::NamedObject> AML::Namespace::find_object(const AML::NameString& relative_base, const AML::NameString& relative_path, FindMode mode) | ||||
| 	{ | ||||
| 		auto canonical_path = resolve_path(relative_base, relative_path); | ||||
| 		LockGuard _(m_object_mutex); | ||||
| 
 | ||||
| 		auto canonical_path = resolve_path(relative_base, relative_path, mode); | ||||
| 		if (!canonical_path.has_value()) | ||||
| 			return nullptr; | ||||
| 		if (canonical_path->path.empty()) | ||||
| 
 | ||||
| 		if (canonical_path->sv() == "\\"sv) | ||||
| 			return this; | ||||
| 
 | ||||
| 		BAN::RefPtr<NamedObject> node = this; | ||||
| 		for (const auto& seg : canonical_path->path) | ||||
| 		{ | ||||
| 			// Resolve path validates that all nodes are scopes
 | ||||
| 			ASSERT(node->is_scope()); | ||||
| 			node = static_cast<Scope*>(node.ptr())->objects[seg]; | ||||
| 		} | ||||
| 
 | ||||
| 		return node; | ||||
| 		auto it = m_objects.find(canonical_path.value()); | ||||
| 		if (it == m_objects.end()) | ||||
| 			return {}; | ||||
| 		return it->value; | ||||
| 	} | ||||
| 
 | ||||
| 	bool AML::Namespace::add_named_object(ParseContext& parse_context, const AML::NameString& object_path, BAN::RefPtr<NamedObject> object) | ||||
| 	{ | ||||
| 		LockGuard _(m_object_mutex); | ||||
| 
 | ||||
| 		ASSERT(!object_path.path.empty()); | ||||
| 		ASSERT(object_path.path.back() == object->name); | ||||
| 
 | ||||
| 		auto parent_path = object_path; | ||||
| 		parent_path.path.pop_back(); | ||||
| 		auto canonical_path = resolve_path(parse_context.scope, object_path, FindMode::ForceAbsolute, false); | ||||
| 		ASSERT(canonical_path.has_value()); | ||||
| 		ASSERT(!canonical_path->empty()); | ||||
| 
 | ||||
| 		auto parent_object = find_object(parse_context.scope, parent_path); | ||||
| 		if (!parent_object) | ||||
| 		if (m_objects.contains(canonical_path.value())) | ||||
| 		{ | ||||
| 			AML_ERROR("Parent object not found"); | ||||
| 			AML_ERROR("Object '{}' already exists", canonical_path.value()); | ||||
| 			return false; | ||||
| 		} | ||||
| 
 | ||||
| 		if (!parent_object->is_scope()) | ||||
| 		{ | ||||
| 			AML_ERROR("Parent object is not a scope"); | ||||
| 			return false; | ||||
| 		} | ||||
| 		auto canonical_scope = AML::NameString(canonical_path.value()); | ||||
| 
 | ||||
| 		auto* parent_scope = static_cast<Scope*>(parent_object.ptr()); | ||||
| 		if (parent_scope->objects.contains(object->name)) | ||||
| 		{ | ||||
| 			AML_ERROR("Object already exists"); | ||||
| 			return false; | ||||
| 		} | ||||
| 
 | ||||
| 		object->parent = parent_scope; | ||||
| 
 | ||||
| 		MUST(parent_scope->objects.insert(object->name, object)); | ||||
| 
 | ||||
| 		auto canonical_scope = resolve_path(parse_context.scope, object_path); | ||||
| 		ASSERT(canonical_scope.has_value()); | ||||
| 		MUST(m_objects.insert(canonical_path.value(), object)); | ||||
| 		if (object->is_scope()) | ||||
| 		{ | ||||
| 			auto* scope = static_cast<Scope*>(object.ptr()); | ||||
| 			scope->scope = canonical_scope.value(); | ||||
| 			scope->scope = canonical_scope; | ||||
| 		} | ||||
| 		MUST(parse_context.created_objects.push_back(BAN::move(canonical_scope.release_value()))); | ||||
| 
 | ||||
| 		MUST(parse_context.created_objects.push_back(canonical_scope)); | ||||
| 
 | ||||
| 		return true; | ||||
| 	} | ||||
| 
 | ||||
| 	bool AML::Namespace::remove_named_object(const AML::NameString& absolute_path) | ||||
| 	{ | ||||
| 		auto object = find_object({}, absolute_path); | ||||
| 		if (!object) | ||||
| 		LockGuard _(m_object_mutex); | ||||
| 
 | ||||
| 		auto canonical_path = resolve_path({}, absolute_path, FindMode::ForceAbsolute); | ||||
| 		if (!canonical_path.has_value()) | ||||
| 		{ | ||||
| 			AML_ERROR("Object {} not found", absolute_path); | ||||
| 			AML_ERROR("Trying to delete non-existent object '{}'", absolute_path); | ||||
| 			return false; | ||||
| 		} | ||||
| 
 | ||||
| 		if (object.ptr() == this) | ||||
| 		if (canonical_path->empty()) | ||||
| 		{ | ||||
| 			AML_ERROR("Trying to remove root object"); | ||||
| 			AML_ERROR("Trying to remove root namespace"); | ||||
| 			return false; | ||||
| 		} | ||||
| 
 | ||||
| 		auto parent = object->parent; | ||||
| 		ASSERT(parent->is_scope()); | ||||
| 
 | ||||
| 		auto* parent_scope = static_cast<Scope*>(parent.ptr()); | ||||
| 		parent_scope->objects.remove(object->name); | ||||
| 		ASSERT(m_objects.contains(canonical_path.value())); | ||||
| 		m_objects.remove(canonical_path.value()); | ||||
| 
 | ||||
| 		return true; | ||||
| 	} | ||||
|  | @ -202,6 +192,7 @@ namespace Kernel::ACPI | |||
| 	{ | ||||
| 		ASSERT(!s_root_namespace); | ||||
| 		s_root_namespace = MUST(BAN::RefPtr<Namespace>::create(NameSeg("\\"sv))); | ||||
| 		s_root_namespace->scope = AML::NameString("\\"sv); | ||||
| 
 | ||||
| 		Integer::Constants::Zero = MUST(BAN::RefPtr<Integer>::create(0, true)); | ||||
| 		Integer::Constants::One = MUST(BAN::RefPtr<Integer>::create(1, true)); | ||||
|  | @ -212,7 +203,7 @@ namespace Kernel::ACPI | |||
| 
 | ||||
| 		// Add predefined namespaces
 | ||||
| #define ADD_PREDEFIED_NAMESPACE(NAME) \ | ||||
| 			ASSERT(s_root_namespace->add_named_object(context, AML::NameString("\\" NAME), MUST(BAN::RefPtr<AML::Namespace>::create(NameSeg(NAME))))); | ||||
| 			ASSERT(s_root_namespace->add_named_object(context, AML::NameString("\\" NAME), MUST(BAN::RefPtr<AML::Device>::create(NameSeg(NAME))))); | ||||
| 		ADD_PREDEFIED_NAMESPACE("_GPE"sv); | ||||
| 		ADD_PREDEFIED_NAMESPACE("_PR"sv); | ||||
| 		ADD_PREDEFIED_NAMESPACE("_SB"sv); | ||||
|  | @ -220,11 +211,19 @@ namespace Kernel::ACPI | |||
| 		ADD_PREDEFIED_NAMESPACE("_TZ"sv); | ||||
| #undef ADD_PREDEFIED_NAMESPACE | ||||
| 
 | ||||
| 		// Add dummy \_OSI
 | ||||
| 		MUST(s_osi_aml_data.push_back(static_cast<uint8_t>(Byte::ReturnOp))); | ||||
| 		MUST(s_osi_aml_data.push_back(static_cast<uint8_t>(Byte::ZeroOp))); | ||||
| 		// Add \_OSI that returns true for Linux compatibility
 | ||||
| 		auto osi = MUST(BAN::RefPtr<AML::Method>::create(NameSeg("_OSI"sv), 1, false, 0)); | ||||
| 		osi->term_list = s_osi_aml_data.span(); | ||||
| 		osi->override_function = [](AML::ParseContext& context) -> BAN::RefPtr<AML::Node> { | ||||
| 			ASSERT(context.method_args[0]); | ||||
| 			auto arg = context.method_args[0]->evaluate(); | ||||
| 			if (!arg || arg->type != AML::Node::Type::String) | ||||
| 			{ | ||||
| 				AML_ERROR("Invalid _OSI argument"); | ||||
| 				return {}; | ||||
| 			} | ||||
| 			auto string = static_cast<AML::String*>(arg.ptr()); | ||||
| 			return string->string == "Linux" ? AML::Integer::Constants::Ones : AML::Integer::Constants::Zero; | ||||
| 		}; | ||||
| 		ASSERT(s_root_namespace->add_named_object(context, AML::NameString("\\_OSI"), osi)); | ||||
| 
 | ||||
| 		return s_root_namespace; | ||||
|  |  | |||
|  | @ -10,6 +10,7 @@ | |||
| #include <kernel/ACPI/AML/Mutex.h> | ||||
| #include <kernel/ACPI/AML/Names.h> | ||||
| #include <kernel/ACPI/AML/Node.h> | ||||
| #include <kernel/ACPI/AML/Notify.h> | ||||
| #include <kernel/ACPI/AML/Package.h> | ||||
| #include <kernel/ACPI/AML/ParseContext.h> | ||||
| #include <kernel/ACPI/AML/PowerResource.h> | ||||
|  | @ -21,6 +22,7 @@ | |||
| #include <kernel/ACPI/AML/String.h> | ||||
| #include <kernel/ACPI/AML/ThermalZone.h> | ||||
| #include <kernel/ACPI/AML/Utils.h> | ||||
| #include <kernel/ACPI/AML/While.h> | ||||
| 
 | ||||
| namespace Kernel::ACPI | ||||
| { | ||||
|  | @ -163,6 +165,8 @@ namespace Kernel::ACPI | |||
| 				return AML::Scope::parse(context); | ||||
| 			case AML::Byte::IfOp: | ||||
| 				return AML::IfElse::parse(context); | ||||
| 			case AML::Byte::WhileOp: | ||||
| 				return AML::While::parse(context); | ||||
| 			case AML::Byte::StoreOp: | ||||
| 				return AML::Store::parse(context); | ||||
| 			case AML::Byte::DerefOfOp: | ||||
|  | @ -170,6 +174,11 @@ namespace Kernel::ACPI | |||
| 				return AML::Reference::parse(context); | ||||
| 			case AML::Byte::IndexOp: | ||||
| 				return AML::Index::parse(context); | ||||
| 			case AML::Byte::NotifyOp: | ||||
| 				return AML::Notify::parse(context); | ||||
| 			case AML::Byte::NoopOp: | ||||
| 				context.aml_data = context.aml_data.slice(1); | ||||
| 				return ParseResult::Success; | ||||
| 			case AML::Byte::ReturnOp: | ||||
| 			{ | ||||
| 				context.aml_data = context.aml_data.slice(1); | ||||
|  | @ -191,7 +200,7 @@ namespace Kernel::ACPI | |||
| 			auto name_string = AML::NameString::parse(context.aml_data); | ||||
| 			if (!name_string.has_value()) | ||||
| 				return ParseResult::Failure; | ||||
| 			auto aml_object = Namespace::root_namespace()->find_object(context.scope, name_string.value()); | ||||
| 			auto aml_object = Namespace::root_namespace()->find_object(context.scope, name_string.value(), Namespace::FindMode::Normal); | ||||
| 			if (!aml_object) | ||||
| 			{ | ||||
| 				AML_ERROR("NameString {} not found in namespace", name_string.value()); | ||||
|  | @ -201,7 +210,7 @@ namespace Kernel::ACPI | |||
| 			{ | ||||
| 				auto* method = static_cast<AML::Method*>(aml_object.ptr()); | ||||
| 
 | ||||
| 				Method::Arguments args; | ||||
| 				BAN::Array<BAN::RefPtr<AML::Node>, 7> args; | ||||
| 				for (uint8_t i = 0; i < method->arg_count; i++) | ||||
| 				{ | ||||
| 					auto arg = AML::parse_object(context); | ||||
|  | @ -213,7 +222,16 @@ namespace Kernel::ACPI | |||
| 					args[i] = MUST(BAN::RefPtr<AML::Register>::create(arg.node())); | ||||
| 				} | ||||
| 
 | ||||
| 				auto result = method->evaluate(args, context.sync_stack); | ||||
| 				auto result = method->invoke_with_sync_stack( | ||||
| 					context.sync_stack, | ||||
| 					args[0], | ||||
| 					args[1], | ||||
| 					args[2], | ||||
| 					args[3], | ||||
| 					args[4], | ||||
| 					args[5], | ||||
| 					args[6] | ||||
| 				); | ||||
| 				if (!result.has_value()) | ||||
| 				{ | ||||
| 					AML_ERROR("Failed to evaluate {}", name_string.value()); | ||||
|  |  | |||
|  | @ -1,6 +1,8 @@ | |||
| #include <kernel/ACPI/AML/Device.h> | ||||
| #include <kernel/ACPI/AML/Integer.h> | ||||
| #include <kernel/ACPI/AML/ParseContext.h> | ||||
| #include <kernel/ACPI/AML/Pkg.h> | ||||
| #include <kernel/ACPI/AML/Region.h> | ||||
| #include <kernel/ACPI/AML/Scope.h> | ||||
| 
 | ||||
| namespace Kernel::ACPI | ||||
|  | @ -20,15 +22,15 @@ namespace Kernel::ACPI | |||
| 		if (!name_string.has_value()) | ||||
| 			return ParseResult::Failure; | ||||
| 
 | ||||
| 		auto named_object = Namespace::root_namespace()->find_object(context.scope, name_string.value()); | ||||
| 		auto named_object = Namespace::root_namespace()->find_object(context.scope, name_string.value(), Namespace::FindMode::Normal); | ||||
| 		if (!named_object) | ||||
| 		{ | ||||
| 			AML_ERROR("Scope name {} not found in namespace", name_string.value()); | ||||
| 			AML_ERROR("Scope '{}' not found in namespace", name_string.value()); | ||||
| 			return ParseResult::Failure; | ||||
| 		} | ||||
| 		if (!named_object->is_scope()) | ||||
| 		{ | ||||
| 			AML_ERROR("Scope name {} does not name a namespace", name_string.value()); | ||||
| 			AML_ERROR("Scope '{}' does not name a namespace", name_string.value()); | ||||
| 			return ParseResult::Failure; | ||||
| 		} | ||||
| 
 | ||||
|  | @ -38,12 +40,12 @@ namespace Kernel::ACPI | |||
| 
 | ||||
| 	AML::ParseResult AML::Scope::enter_context_and_parse_term_list(ParseContext& outer_context, const AML::NameString& name_string, BAN::ConstByteSpan aml_data) | ||||
| 	{ | ||||
| 		auto resolved_scope = Namespace::root_namespace()->resolve_path(outer_context.scope, name_string); | ||||
| 		auto resolved_scope = Namespace::root_namespace()->resolve_path(outer_context.scope, name_string, Namespace::FindMode::Normal); | ||||
| 		if (!resolved_scope.has_value()) | ||||
| 			return ParseResult::Failure; | ||||
| 
 | ||||
| 		ParseContext scope_context; | ||||
| 		scope_context.scope = resolved_scope.release_value(); | ||||
| 		scope_context.scope = AML::NameString(resolved_scope.release_value()); | ||||
| 		scope_context.aml_data = aml_data; | ||||
| 		scope_context.method_args = outer_context.method_args; | ||||
| 		while (scope_context.aml_data.size() > 0) | ||||
|  | @ -64,19 +66,26 @@ namespace Kernel::ACPI | |||
| 		return ParseResult::Success; | ||||
| 	} | ||||
| 
 | ||||
| 	void AML::Scope::debug_print(int indent) const | ||||
| 	static BAN::Optional<uint64_t> evaluate_or_invoke(BAN::RefPtr<AML::Node> object) | ||||
| 	{ | ||||
| 		AML_DEBUG_PRINT_INDENT(indent); | ||||
| 		AML_DEBUG_PRINT("Scope "); | ||||
| 		name.debug_print(); | ||||
| 		AML_DEBUG_PRINTLN(" {"); | ||||
| 		for (const auto& [name, object] : objects) | ||||
| 		if (object->type != AML::Node::Type::Method) | ||||
| 			return object->as_integer(); | ||||
| 
 | ||||
| 		auto* method = static_cast<AML::Method*>(object.ptr()); | ||||
| 		if (method->arg_count != 0) | ||||
| 		{ | ||||
| 			object->debug_print(indent + 1); | ||||
| 			AML_DEBUG_PRINTLN(""); | ||||
| 			AML_ERROR("Method has {} arguments, expected 0", method->arg_count); | ||||
| 			return {}; | ||||
| 		} | ||||
| 		AML_DEBUG_PRINT_INDENT(indent); | ||||
| 		AML_DEBUG_PRINT("}"); | ||||
| 
 | ||||
| 		auto result = method->invoke(); | ||||
| 		if (!result.has_value()) | ||||
| 		{ | ||||
| 			AML_ERROR("Failed to evaluate method"); | ||||
| 			return {}; | ||||
| 		} | ||||
| 
 | ||||
| 		return result.value() ? result.value()->as_integer() : BAN::Optional<uint64_t>(); | ||||
| 	} | ||||
| 
 | ||||
| 	bool AML::initialize_scope(BAN::RefPtr<AML::Scope> scope) | ||||
|  | @ -85,64 +94,100 @@ namespace Kernel::ACPI | |||
| 		AML_DEBUG_PRINTLN("Initializing {}", scope->scope); | ||||
| #endif | ||||
| 
 | ||||
| 		if (auto reg = Namespace::root_namespace()->find_object(scope->scope, AML::NameString("_REG"sv), Namespace::FindMode::ForceAbsolute)) | ||||
| 		{ | ||||
| 			bool embedded_controller = false; | ||||
| 			Namespace::for_each_child(scope->scope, | ||||
| 				[&](const auto&, auto& child) | ||||
| 				{ | ||||
| 					if (child->type != AML::Node::Type::OpRegion) | ||||
| 						return; | ||||
| 					auto* region = static_cast<AML::OpRegion*>(child.ptr()); | ||||
| 					if (region->region_space == AML::OpRegion::RegionSpace::EmbeddedController) | ||||
| 						embedded_controller = true; | ||||
| 				} | ||||
| 			); | ||||
| 			if (embedded_controller) | ||||
| 			{ | ||||
| 				if (reg->type != AML::Node::Type::Method) | ||||
| 				{ | ||||
| 					AML_ERROR("Object {}._REG is not a method", scope->scope); | ||||
| 					return false; | ||||
| 				} | ||||
| 
 | ||||
| 				auto* method = static_cast<Method*>(reg.ptr()); | ||||
| 				if (method->arg_count != 2) | ||||
| 				{ | ||||
| 					AML_ERROR("Method {}._REG has {} arguments, expected 2", scope->scope, method->arg_count); | ||||
| 					return false; | ||||
| 				} | ||||
| 
 | ||||
| 				BAN::RefPtr<AML::Node> embedded_controller = MUST(BAN::RefPtr<AML::Integer>::create(static_cast<uint64_t>(AML::OpRegion::RegionSpace::EmbeddedController))); | ||||
| 
 | ||||
| 				if (!method->invoke(embedded_controller, AML::Integer::Constants::One).has_value()) | ||||
| 				{ | ||||
| 					AML_ERROR("Failed to evaluate {}._REG(EmbeddedController, 1), ignoring device", scope->scope); | ||||
| 					return false; | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		bool run_ini = true; | ||||
| 		bool init_children = true; | ||||
| 
 | ||||
| 		auto it = scope->objects.find(NameSeg("_STA"sv)); | ||||
| 		if (scope->type != AML::Node::Type::Namespace && it != scope->objects.end() && it->value->type == Node::Type::Method) | ||||
| 		if (auto sta = Namespace::root_namespace()->find_object(scope->scope, AML::NameString("_STA"sv), Namespace::FindMode::ForceAbsolute)) | ||||
| 		{ | ||||
| 			auto* method = static_cast<Method*>(it->value.ptr()); | ||||
| 			if (method->arg_count != 0) | ||||
| 			{ | ||||
| 				AML_ERROR("Method {}._STA has {} arguments, expected 0", scope->scope, method->arg_count); | ||||
| 				return false; | ||||
| 			} | ||||
| 			BAN::Vector<uint8_t> sync_stack; | ||||
| 			auto result = method->evaluate({}, sync_stack); | ||||
| 			auto result = evaluate_or_invoke(sta); | ||||
| 			if (!result.has_value()) | ||||
| 			{ | ||||
| 				AML_ERROR("Failed to evaluate {}._STA, ignoring device", scope->scope); | ||||
| 				return true; | ||||
| 			} | ||||
| 			auto result_value = result.has_value() ? result.value()->as_integer() : BAN::Optional<uint64_t>(); | ||||
| 			if (!result_value.has_value()) | ||||
| 			{ | ||||
| 				AML_ERROR("Failed to evaluate {}._STA, return value could not be resolved to integer", scope->scope); | ||||
| 				AML_ERROR("  Return value: "); | ||||
| 				result.value()->debug_print(0); | ||||
| 				return false; | ||||
| 			} | ||||
| 			run_ini = (result_value.value() & 0x01); | ||||
| 			init_children = run_ini || (result_value.value() & 0x02); | ||||
| 
 | ||||
| 			run_ini = (result.value() & 0x01); | ||||
| 			init_children = run_ini || (result.value() & 0x02); | ||||
| 		} | ||||
| 
 | ||||
| 		if (run_ini) | ||||
| 		{ | ||||
| 			auto it = scope->objects.find(NameSeg("_STA"sv)); | ||||
| 			if (it != scope->objects.end() && it->value->type == Node::Type::Method) | ||||
| 			auto ini = Namespace::root_namespace()->find_object(scope->scope, AML::NameString("_INI"sv), Namespace::FindMode::ForceAbsolute); | ||||
| 			if (ini) | ||||
| 			{ | ||||
| 				auto* method = static_cast<Method*>(it->value.ptr()); | ||||
| 				if (ini->type != AML::Node::Type::Method) | ||||
| 				{ | ||||
| 					AML_ERROR("Object {}._INI is not a method", scope->scope); | ||||
| 					return false; | ||||
| 				} | ||||
| 
 | ||||
| 				auto* method = static_cast<Method*>(ini.ptr()); | ||||
| 				if (method->arg_count != 0) | ||||
| 				{ | ||||
| 					AML_ERROR("Method {}._INI has {} arguments, expected 0", scope->scope, method->arg_count); | ||||
| 					return false; | ||||
| 				} | ||||
| 				BAN::Vector<uint8_t> sync_stack; | ||||
| 				method->evaluate({}, sync_stack); | ||||
| 
 | ||||
| 				auto result = method->invoke(); | ||||
| 				if (!result.has_value()) | ||||
| 				{ | ||||
| 					AML_ERROR("Failed to evaluate {}._INI, ignoring device", scope->scope); | ||||
| 					return true; | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		bool success = true; | ||||
| 		if (init_children) | ||||
| 		{ | ||||
| 			for (auto& [_, child] : scope->objects) | ||||
| 			Namespace::root_namespace()->for_each_child(scope->scope, | ||||
| 				[&](const auto&, auto& child) | ||||
| 				{ | ||||
| 					if (!child->is_scope()) | ||||
| 					continue; | ||||
| 						return; | ||||
| 					auto* child_scope = static_cast<Scope*>(child.ptr()); | ||||
| 					if (!initialize_scope(child_scope)) | ||||
| 						success = false; | ||||
| 				} | ||||
| 			); | ||||
| 		} | ||||
| 		return success; | ||||
| 	} | ||||
|  |  | |||
|  | @ -194,6 +194,9 @@ namespace Kernel | |||
| 					goto done; | ||||
| 				} | ||||
| 
 | ||||
| 				// Demand paging is only supported in userspace
 | ||||
| 				if (thread.is_userspace()) | ||||
| 				{ | ||||
| 					// Try demand paging on non present pages
 | ||||
| 					PageFaultError page_fault_error; | ||||
| 					page_fault_error.raw = error; | ||||
|  | @ -214,6 +217,7 @@ namespace Kernel | |||
| 						} | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| #if __enable_sse | ||||
| 			else if (isr == ISR::DeviceNotAvailable) | ||||
| 			{ | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue