brintos

brintos / linux-shallow public Read only

0
0
Text · 15.9 KiB · ecf793f Raw
532 lines · c
1// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.02/******************************************************************************3 *4 * Module Name: dspkginit - Completion of deferred package initialization5 *6 * Copyright (C) 2000 - 2023, Intel Corp.7 *8 *****************************************************************************/9 10#include <acpi/acpi.h>11#include "accommon.h"12#include "acnamesp.h"13#include "amlcode.h"14#include "acdispat.h"15#include "acinterp.h"16#include "acparser.h"17 18#define _COMPONENT          ACPI_NAMESPACE19ACPI_MODULE_NAME("dspkginit")20 21/* Local prototypes */22static void23acpi_ds_resolve_package_element(union acpi_operand_object **element);24 25/*******************************************************************************26 *27 * FUNCTION:    acpi_ds_build_internal_package_obj28 *29 * PARAMETERS:  walk_state      - Current walk state30 *              op              - Parser object to be translated31 *              element_count   - Number of elements in the package - this is32 *                                the num_elements argument to Package()33 *              obj_desc_ptr    - Where the ACPI internal object is returned34 *35 * RETURN:      Status36 *37 * DESCRIPTION: Translate a parser Op package object to the equivalent38 *              namespace object39 *40 * NOTE: The number of elements in the package will be always be the num_elements41 * count, regardless of the number of elements in the package list. If42 * num_elements is smaller, only that many package list elements are used.43 * if num_elements is larger, the Package object is padded out with44 * objects of type Uninitialized (as per ACPI spec.)45 *46 * Even though the ASL compilers do not allow num_elements to be smaller47 * than the Package list length (for the fixed length package opcode), some48 * BIOS code modifies the AML on the fly to adjust the num_elements, and49 * this code compensates for that. This also provides compatibility with50 * other AML interpreters.51 *52 ******************************************************************************/53 54acpi_status55acpi_ds_build_internal_package_obj(struct acpi_walk_state *walk_state,56				   union acpi_parse_object *op,57				   u32 element_count,58				   union acpi_operand_object **obj_desc_ptr)59{60	union acpi_parse_object *arg;61	union acpi_parse_object *parent;62	union acpi_operand_object *obj_desc = NULL;63	acpi_status status = AE_OK;64	u8 module_level_code = FALSE;65	u16 reference_count;66	u32 index;67	u32 i;68 69	ACPI_FUNCTION_TRACE(ds_build_internal_package_obj);70 71	/* Check if we are executing module level code */72 73	if (walk_state->parse_flags & ACPI_PARSE_MODULE_LEVEL) {74		module_level_code = TRUE;75	}76 77	/* Find the parent of a possibly nested package */78 79	parent = op->common.parent;80	while ((parent->common.aml_opcode == AML_PACKAGE_OP) ||81	       (parent->common.aml_opcode == AML_VARIABLE_PACKAGE_OP)) {82		parent = parent->common.parent;83	}84 85	/*86	 * If we are evaluating a Named package object of the form:87	 *      Name (xxxx, Package)88	 * the package object already exists, otherwise it must be created.89	 */90	obj_desc = *obj_desc_ptr;91	if (!obj_desc) {92		obj_desc = acpi_ut_create_internal_object(ACPI_TYPE_PACKAGE);93		*obj_desc_ptr = obj_desc;94		if (!obj_desc) {95			return_ACPI_STATUS(AE_NO_MEMORY);96		}97 98		obj_desc->package.node = parent->common.node;99	}100 101	if (obj_desc->package.flags & AOPOBJ_DATA_VALID) {	/* Just in case */102		return_ACPI_STATUS(AE_OK);103	}104 105	/*106	 * Allocate the element array (array of pointers to the individual107	 * objects) if necessary. the count is based on the num_elements108	 * parameter. Add an extra pointer slot so that the list is always109	 * null terminated.110	 */111	if (!obj_desc->package.elements) {112		obj_desc->package.elements = ACPI_ALLOCATE_ZEROED(((acpi_size)113								   element_count114								   +115								   1) *116								  sizeof(void117									 *));118 119		if (!obj_desc->package.elements) {120			acpi_ut_delete_object_desc(obj_desc);121			return_ACPI_STATUS(AE_NO_MEMORY);122		}123 124		obj_desc->package.count = element_count;125	}126 127	/* First arg is element count. Second arg begins the initializer list */128 129	arg = op->common.value.arg;130	arg = arg->common.next;131 132	/*133	 * If we are executing module-level code, we will defer the134	 * full resolution of the package elements in order to support135	 * forward references from the elements. This provides136	 * compatibility with other ACPI implementations.137	 */138	if (module_level_code) {139		obj_desc->package.aml_start = walk_state->aml;140		obj_desc->package.aml_length = 0;141 142		ACPI_DEBUG_PRINT_RAW((ACPI_DB_PARSE,143				      "%s: Deferring resolution of Package elements\n",144				      ACPI_GET_FUNCTION_NAME));145	}146 147	/*148	 * Initialize the elements of the package, up to the num_elements count.149	 * Package is automatically padded with uninitialized (NULL) elements150	 * if num_elements is greater than the package list length. Likewise,151	 * Package is truncated if num_elements is less than the list length.152	 */153	for (i = 0; arg && (i < element_count); i++) {154		if (arg->common.aml_opcode == AML_INT_RETURN_VALUE_OP) {155			if (!arg->common.node) {156				/*157				 * This is the case where an expression has returned a value.158				 * The use of expressions (term_args) within individual159				 * package elements is not supported by the AML interpreter,160				 * even though the ASL grammar supports it. Example:161				 *162				 *      Name (INT1, 0x1234)163				 *164				 *      Name (PKG3, Package () {165				 *          Add (INT1, 0xAAAA0000)166				 *      })167				 *168				 *  1) No known AML interpreter supports this type of construct169				 *  2) This fixes a fault if the construct is encountered170				 */171				ACPI_EXCEPTION((AE_INFO, AE_SUPPORT,172						"Expressions within package elements are not supported"));173 174				/* Cleanup the return object, it is not needed */175 176				acpi_ut_remove_reference(walk_state->results->177							 results.obj_desc[0]);178				return_ACPI_STATUS(AE_SUPPORT);179			}180 181			if (arg->common.node->type == ACPI_TYPE_METHOD) {182				/*183				 * A method reference "looks" to the parser to be a method184				 * invocation, so we special case it here185				 */186				arg->common.aml_opcode = AML_INT_NAMEPATH_OP;187				status =188				    acpi_ds_build_internal_object(walk_state,189								  arg,190								  &obj_desc->191								  package.192								  elements[i]);193			} else {194				/* This package element is already built, just get it */195 196				obj_desc->package.elements[i] =197				    ACPI_CAST_PTR(union acpi_operand_object,198						  arg->common.node);199			}200		} else {201			status =202			    acpi_ds_build_internal_object(walk_state, arg,203							  &obj_desc->package.204							  elements[i]);205			if (status == AE_NOT_FOUND) {206				ACPI_ERROR((AE_INFO, "%-48s",207					    "****DS namepath not found"));208			}209 210			if (!module_level_code) {211				/*212				 * Initialize this package element. This function handles the213				 * resolution of named references within the package.214				 * Forward references from module-level code are deferred215				 * until all ACPI tables are loaded.216				 */217				acpi_ds_init_package_element(0,218							     obj_desc->package.219							     elements[i], NULL,220							     &obj_desc->package.221							     elements[i]);222			}223		}224 225		if (*obj_desc_ptr) {226 227			/* Existing package, get existing reference count */228 229			reference_count =230			    (*obj_desc_ptr)->common.reference_count;231			if (reference_count > 1) {232 233				/* Make new element ref count match original ref count */234				/* TBD: Probably need an acpi_ut_add_references function */235 236				for (index = 0;237				     index < ((u32)reference_count - 1);238				     index++) {239					acpi_ut_add_reference((obj_desc->240							       package.241							       elements[i]));242				}243			}244		}245 246		arg = arg->common.next;247	}248 249	/* Check for match between num_elements and actual length of package_list */250 251	if (arg) {252		/*253		 * num_elements was exhausted, but there are remaining elements in254		 * the package_list. Truncate the package to num_elements.255		 *256		 * Note: technically, this is an error, from ACPI spec: "It is an257		 * error for NumElements to be less than the number of elements in258		 * the PackageList". However, we just print a message and no259		 * exception is returned. This provides compatibility with other260		 * ACPI implementations. Some firmware implementations will alter261		 * the num_elements on the fly, possibly creating this type of262		 * ill-formed package object.263		 */264		while (arg) {265			/*266			 * We must delete any package elements that were created earlier267			 * and are not going to be used because of the package truncation.268			 */269			if (arg->common.node) {270				acpi_ut_remove_reference(ACPI_CAST_PTR271							 (union272							  acpi_operand_object,273							  arg->common.node));274				arg->common.node = NULL;275			}276 277			/* Find out how many elements there really are */278 279			i++;280			arg = arg->common.next;281		}282 283		ACPI_INFO(("Actual Package length (%u) is larger than "284			   "NumElements field (%u), truncated",285			   i, element_count));286	} else if (i < element_count) {287		/*288		 * Arg list (elements) was exhausted, but we did not reach289		 * num_elements count.290		 *291		 * Note: this is not an error, the package is padded out292		 * with NULLs as per the ACPI specification.293		 */294		ACPI_DEBUG_PRINT_RAW((ACPI_DB_INFO,295				      "%s: Package List length (%u) smaller than NumElements "296				      "count (%u), padded with null elements\n",297				      ACPI_GET_FUNCTION_NAME, i,298				      element_count));299	}300 301	/* Module-level packages will be resolved later */302 303	if (!module_level_code) {304		obj_desc->package.flags |= AOPOBJ_DATA_VALID;305	}306 307	op->common.node = ACPI_CAST_PTR(struct acpi_namespace_node, obj_desc);308	return_ACPI_STATUS(status);309}310 311/*******************************************************************************312 *313 * FUNCTION:    acpi_ds_init_package_element314 *315 * PARAMETERS:  acpi_pkg_callback316 *317 * RETURN:      Status318 *319 * DESCRIPTION: Resolve a named reference element within a package object320 *321 ******************************************************************************/322 323acpi_status324acpi_ds_init_package_element(u8 object_type,325			     union acpi_operand_object *source_object,326			     union acpi_generic_state *state, void *context)327{328	union acpi_operand_object **element_ptr;329 330	ACPI_FUNCTION_TRACE(ds_init_package_element);331 332	if (!source_object) {333		return_ACPI_STATUS(AE_OK);334	}335 336	/*337	 * The following code is a bit of a hack to workaround a (current)338	 * limitation of the acpi_pkg_callback interface. We need a pointer339	 * to the location within the element array because a new object340	 * may be created and stored there.341	 */342	if (context) {343 344		/* A direct call was made to this function */345 346		element_ptr = (union acpi_operand_object **)context;347	} else {348		/* Call came from acpi_ut_walk_package_tree */349 350		element_ptr = state->pkg.this_target_obj;351	}352 353	/* We are only interested in reference objects/elements */354 355	if (source_object->common.type == ACPI_TYPE_LOCAL_REFERENCE) {356 357		/* Attempt to resolve the (named) reference to a namespace node */358 359		acpi_ds_resolve_package_element(element_ptr);360	} else if (source_object->common.type == ACPI_TYPE_PACKAGE) {361		source_object->package.flags |= AOPOBJ_DATA_VALID;362	}363 364	return_ACPI_STATUS(AE_OK);365}366 367/*******************************************************************************368 *369 * FUNCTION:    acpi_ds_resolve_package_element370 *371 * PARAMETERS:  element_ptr         - Pointer to a reference object372 *373 * RETURN:      Possible new element is stored to the indirect element_ptr374 *375 * DESCRIPTION: Resolve a package element that is a reference to a named376 *              object.377 *378 ******************************************************************************/379 380static void381acpi_ds_resolve_package_element(union acpi_operand_object **element_ptr)382{383	acpi_status status;384	acpi_status status2;385	union acpi_generic_state scope_info;386	union acpi_operand_object *element = *element_ptr;387	struct acpi_namespace_node *resolved_node;388	struct acpi_namespace_node *original_node;389	char *external_path = "";390	acpi_object_type type;391 392	ACPI_FUNCTION_TRACE(ds_resolve_package_element);393 394	/* Check if reference element is already resolved */395 396	if (element->reference.resolved) {397		ACPI_DEBUG_PRINT_RAW((ACPI_DB_PARSE,398				      "%s: Package element is already resolved\n",399				      ACPI_GET_FUNCTION_NAME));400 401		return_VOID;402	}403 404	/* Element must be a reference object of correct type */405 406	scope_info.scope.node = element->reference.node;	/* Prefix node */407 408	status = acpi_ns_lookup(&scope_info, (char *)element->reference.aml,409				ACPI_TYPE_ANY, ACPI_IMODE_EXECUTE,410				ACPI_NS_SEARCH_PARENT | ACPI_NS_DONT_OPEN_SCOPE,411				NULL, &resolved_node);412	if (ACPI_FAILURE(status)) {413		if ((status == AE_NOT_FOUND)414		    && acpi_gbl_ignore_package_resolution_errors) {415			/*416			 * Optionally be silent about the NOT_FOUND case for the referenced417			 * name. Although this is potentially a serious problem,418			 * it can generate a lot of noise/errors on platforms whose419			 * firmware carries around a bunch of unused Package objects.420			 * To disable these errors, set this global to TRUE:421			 *     acpi_gbl_ignore_package_resolution_errors422			 *423			 * If the AML actually tries to use such a package, the unresolved424			 * element(s) will be replaced with NULL elements.425			 */426 427			/* Referenced name not found, set the element to NULL */428 429			acpi_ut_remove_reference(*element_ptr);430			*element_ptr = NULL;431			return_VOID;432		}433 434		status2 = acpi_ns_externalize_name(ACPI_UINT32_MAX,435						   (char *)element->reference.436						   aml, NULL, &external_path);437 438		ACPI_EXCEPTION((AE_INFO, status,439				"While resolving a named reference package element - %s",440				external_path));441		if (ACPI_SUCCESS(status2)) {442			ACPI_FREE(external_path);443		}444 445		/* Could not resolve name, set the element to NULL */446 447		acpi_ut_remove_reference(*element_ptr);448		*element_ptr = NULL;449		return_VOID;450	} else if (resolved_node->type == ACPI_TYPE_ANY) {451 452		/* Named reference not resolved, return a NULL package element */453 454		ACPI_ERROR((AE_INFO,455			    "Could not resolve named package element [%4.4s] in [%4.4s]",456			    resolved_node->name.ascii,457			    scope_info.scope.node->name.ascii));458		*element_ptr = NULL;459		return_VOID;460	}461 462	/*463	 * Special handling for Alias objects. We need resolved_node to point464	 * to the Alias target. This effectively "resolves" the alias.465	 */466	if (resolved_node->type == ACPI_TYPE_LOCAL_ALIAS) {467		resolved_node = ACPI_CAST_PTR(struct acpi_namespace_node,468					      resolved_node->object);469	}470 471	/* Update the reference object */472 473	element->reference.resolved = TRUE;474	element->reference.node = resolved_node;475	type = element->reference.node->type;476 477	/*478	 * Attempt to resolve the node to a value before we insert it into479	 * the package. If this is a reference to a common data type,480	 * resolve it immediately. According to the ACPI spec, package481	 * elements can only be "data objects" or method references.482	 * Attempt to resolve to an Integer, Buffer, String or Package.483	 * If cannot, return the named reference (for things like Devices,484	 * Methods, etc.) Buffer Fields and Fields will resolve to simple485	 * objects (int/buf/str/pkg).486	 *487	 * NOTE: References to things like Devices, Methods, Mutexes, etc.488	 * will remain as named references. This behavior is not described489	 * in the ACPI spec, but it appears to be an oversight.490	 */491	original_node = resolved_node;492	status = acpi_ex_resolve_node_to_value(&resolved_node, NULL);493	if (ACPI_FAILURE(status)) {494		return_VOID;495	}496 497	switch (type) {498		/*499		 * These object types are a result of named references, so we will500		 * leave them as reference objects. In other words, these types501		 * have no intrinsic "value".502		 */503	case ACPI_TYPE_DEVICE:504	case ACPI_TYPE_THERMAL:505	case ACPI_TYPE_METHOD:506		break;507 508	case ACPI_TYPE_MUTEX:509	case ACPI_TYPE_POWER:510	case ACPI_TYPE_PROCESSOR:511	case ACPI_TYPE_EVENT:512	case ACPI_TYPE_REGION:513 514		/* acpi_ex_resolve_node_to_value gave these an extra reference */515 516		acpi_ut_remove_reference(original_node->object);517		break;518 519	default:520		/*521		 * For all other types - the node was resolved to an actual522		 * operand object with a value, return the object. Remove523		 * a reference on the existing object.524		 */525		acpi_ut_remove_reference(element);526		*element_ptr = (union acpi_operand_object *)resolved_node;527		break;528	}529 530	return_VOID;531}532