brintos

brintos / linux-shallow public Read only

0
0
Text · 19.3 KiB · eca5051 Raw
682 lines · c
1// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.02/*******************************************************************************3 *4 * Module Name: dsmthdat - control method arguments and local variables5 *6 ******************************************************************************/7 8#include <acpi/acpi.h>9#include "accommon.h"10#include "acdispat.h"11#include "acnamesp.h"12#include "acinterp.h"13 14#define _COMPONENT          ACPI_DISPATCHER15ACPI_MODULE_NAME("dsmthdat")16 17/* Local prototypes */18static void19acpi_ds_method_data_delete_value(u8 type,20				 u32 index, struct acpi_walk_state *walk_state);21 22static acpi_status23acpi_ds_method_data_set_value(u8 type,24			      u32 index,25			      union acpi_operand_object *object,26			      struct acpi_walk_state *walk_state);27 28#ifdef ACPI_OBSOLETE_FUNCTIONS29acpi_object_type30acpi_ds_method_data_get_type(u16 opcode,31			     u32 index, struct acpi_walk_state *walk_state);32#endif33 34/*******************************************************************************35 *36 * FUNCTION:    acpi_ds_method_data_init37 *38 * PARAMETERS:  walk_state          - Current walk state object39 *40 * RETURN:      Status41 *42 * DESCRIPTION: Initialize the data structures that hold the method's arguments43 *              and locals. The data struct is an array of namespace nodes for44 *              each - this allows ref_of and de_ref_of to work properly for these45 *              special data types.46 *47 * NOTES:       walk_state fields are initialized to zero by the48 *              ACPI_ALLOCATE_ZEROED().49 *50 *              A pseudo-Namespace Node is assigned to each argument and local51 *              so that ref_of() can return a pointer to the Node.52 *53 ******************************************************************************/54 55void acpi_ds_method_data_init(struct acpi_walk_state *walk_state)56{57	u32 i;58 59	ACPI_FUNCTION_TRACE(ds_method_data_init);60 61	/* Init the method arguments */62 63	for (i = 0; i < ACPI_METHOD_NUM_ARGS; i++) {64		ACPI_MOVE_32_TO_32(&walk_state->arguments[i].name,65				   NAMEOF_ARG_NTE);66 67		walk_state->arguments[i].name.integer |= (i << 24);68		walk_state->arguments[i].descriptor_type = ACPI_DESC_TYPE_NAMED;69		walk_state->arguments[i].type = ACPI_TYPE_ANY;70		walk_state->arguments[i].flags = ANOBJ_METHOD_ARG;71	}72 73	/* Init the method locals */74 75	for (i = 0; i < ACPI_METHOD_NUM_LOCALS; i++) {76		ACPI_MOVE_32_TO_32(&walk_state->local_variables[i].name,77				   NAMEOF_LOCAL_NTE);78 79		walk_state->local_variables[i].name.integer |= (i << 24);80		walk_state->local_variables[i].descriptor_type =81		    ACPI_DESC_TYPE_NAMED;82		walk_state->local_variables[i].type = ACPI_TYPE_ANY;83		walk_state->local_variables[i].flags = ANOBJ_METHOD_LOCAL;84	}85 86	return_VOID;87}88 89/*******************************************************************************90 *91 * FUNCTION:    acpi_ds_method_data_delete_all92 *93 * PARAMETERS:  walk_state          - Current walk state object94 *95 * RETURN:      None96 *97 * DESCRIPTION: Delete method locals and arguments. Arguments are only98 *              deleted if this method was called from another method.99 *100 ******************************************************************************/101 102void acpi_ds_method_data_delete_all(struct acpi_walk_state *walk_state)103{104	u32 index;105 106	ACPI_FUNCTION_TRACE(ds_method_data_delete_all);107 108	/* Detach the locals */109 110	for (index = 0; index < ACPI_METHOD_NUM_LOCALS; index++) {111		if (walk_state->local_variables[index].object) {112			ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Deleting Local%u=%p\n",113					  index,114					  walk_state->local_variables[index].115					  object));116 117			/* Detach object (if present) and remove a reference */118 119			acpi_ns_detach_object(&walk_state->120					      local_variables[index]);121		}122	}123 124	/* Detach the arguments */125 126	for (index = 0; index < ACPI_METHOD_NUM_ARGS; index++) {127		if (walk_state->arguments[index].object) {128			ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Deleting Arg%u=%p\n",129					  index,130					  walk_state->arguments[index].object));131 132			/* Detach object (if present) and remove a reference */133 134			acpi_ns_detach_object(&walk_state->arguments[index]);135		}136	}137 138	return_VOID;139}140 141/*******************************************************************************142 *143 * FUNCTION:    acpi_ds_method_data_init_args144 *145 * PARAMETERS:  *params         - Pointer to a parameter list for the method146 *              max_param_count - The arg count for this method147 *              walk_state      - Current walk state object148 *149 * RETURN:      Status150 *151 * DESCRIPTION: Initialize arguments for a method. The parameter list is a list152 *              of ACPI operand objects, either null terminated or whose length153 *              is defined by max_param_count.154 *155 ******************************************************************************/156 157acpi_status158acpi_ds_method_data_init_args(union acpi_operand_object **params,159			      u32 max_param_count,160			      struct acpi_walk_state *walk_state)161{162	acpi_status status;163	u32 index = 0;164 165	ACPI_FUNCTION_TRACE_PTR(ds_method_data_init_args, params);166 167	if (!params) {168		ACPI_DEBUG_PRINT((ACPI_DB_EXEC,169				  "No parameter list passed to method\n"));170		return_ACPI_STATUS(AE_OK);171	}172 173	/* Copy passed parameters into the new method stack frame */174 175	while ((index < ACPI_METHOD_NUM_ARGS) &&176	       (index < max_param_count) && params[index]) {177		/*178		 * A valid parameter.179		 * Store the argument in the method/walk descriptor.180		 * Do not copy the arg in order to implement call by reference181		 */182		status =183		    acpi_ds_method_data_set_value(ACPI_REFCLASS_ARG, index,184						  params[index], walk_state);185		if (ACPI_FAILURE(status)) {186			return_ACPI_STATUS(status);187		}188 189		index++;190	}191 192	ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "%u args passed to method\n", index));193	return_ACPI_STATUS(AE_OK);194}195 196/*******************************************************************************197 *198 * FUNCTION:    acpi_ds_method_data_get_node199 *200 * PARAMETERS:  type                - Either ACPI_REFCLASS_LOCAL or201 *                                    ACPI_REFCLASS_ARG202 *              index               - Which Local or Arg whose type to get203 *              walk_state          - Current walk state object204 *              node                - Where the node is returned.205 *206 * RETURN:      Status and node207 *208 * DESCRIPTION: Get the Node associated with a local or arg.209 *210 ******************************************************************************/211 212acpi_status213acpi_ds_method_data_get_node(u8 type,214			     u32 index,215			     struct acpi_walk_state *walk_state,216			     struct acpi_namespace_node **node)217{218	ACPI_FUNCTION_TRACE(ds_method_data_get_node);219 220	/*221	 * Method Locals and Arguments are supported222	 */223	switch (type) {224	case ACPI_REFCLASS_LOCAL:225 226		if (index > ACPI_METHOD_MAX_LOCAL) {227			ACPI_ERROR((AE_INFO,228				    "Local index %u is invalid (max %u)",229				    index, ACPI_METHOD_MAX_LOCAL));230			return_ACPI_STATUS(AE_AML_INVALID_INDEX);231		}232 233		/* Return a pointer to the pseudo-node */234 235		*node = &walk_state->local_variables[index];236		break;237 238	case ACPI_REFCLASS_ARG:239 240		if (index > ACPI_METHOD_MAX_ARG) {241			ACPI_ERROR((AE_INFO,242				    "Arg index %u is invalid (max %u)",243				    index, ACPI_METHOD_MAX_ARG));244			return_ACPI_STATUS(AE_AML_INVALID_INDEX);245		}246 247		/* Return a pointer to the pseudo-node */248 249		*node = &walk_state->arguments[index];250		break;251 252	default:253 254		ACPI_ERROR((AE_INFO, "Type %u is invalid", type));255		return_ACPI_STATUS(AE_TYPE);256	}257 258	return_ACPI_STATUS(AE_OK);259}260 261/*******************************************************************************262 *263 * FUNCTION:    acpi_ds_method_data_set_value264 *265 * PARAMETERS:  type                - Either ACPI_REFCLASS_LOCAL or266 *                                    ACPI_REFCLASS_ARG267 *              index               - Which Local or Arg to get268 *              object              - Object to be inserted into the stack entry269 *              walk_state          - Current walk state object270 *271 * RETURN:      Status272 *273 * DESCRIPTION: Insert an object onto the method stack at entry Opcode:Index.274 *              Note: There is no "implicit conversion" for locals.275 *276 ******************************************************************************/277 278static acpi_status279acpi_ds_method_data_set_value(u8 type,280			      u32 index,281			      union acpi_operand_object *object,282			      struct acpi_walk_state *walk_state)283{284	acpi_status status;285	struct acpi_namespace_node *node;286 287	ACPI_FUNCTION_TRACE(ds_method_data_set_value);288 289	ACPI_DEBUG_PRINT((ACPI_DB_EXEC,290			  "NewObj %p Type %2.2X, Refs=%u [%s]\n", object,291			  type, object->common.reference_count,292			  acpi_ut_get_type_name(object->common.type)));293 294	/* Get the namespace node for the arg/local */295 296	status = acpi_ds_method_data_get_node(type, index, walk_state, &node);297	if (ACPI_FAILURE(status)) {298		return_ACPI_STATUS(status);299	}300 301	/*302	 * Increment ref count so object can't be deleted while installed.303	 * NOTE: We do not copy the object in order to preserve the call by304	 * reference semantics of ACPI Control Method invocation.305	 * (See ACPI Specification 2.0C)306	 */307	acpi_ut_add_reference(object);308 309	/* Install the object */310 311	node->object = object;312	return_ACPI_STATUS(status);313}314 315/*******************************************************************************316 *317 * FUNCTION:    acpi_ds_method_data_get_value318 *319 * PARAMETERS:  type                - Either ACPI_REFCLASS_LOCAL or320 *                                    ACPI_REFCLASS_ARG321 *              index               - Which localVar or argument to get322 *              walk_state          - Current walk state object323 *              dest_desc           - Where Arg or Local value is returned324 *325 * RETURN:      Status326 *327 * DESCRIPTION: Retrieve value of selected Arg or Local for this method328 *              Used only in acpi_ex_resolve_to_value().329 *330 ******************************************************************************/331 332acpi_status333acpi_ds_method_data_get_value(u8 type,334			      u32 index,335			      struct acpi_walk_state *walk_state,336			      union acpi_operand_object **dest_desc)337{338	acpi_status status;339	struct acpi_namespace_node *node;340	union acpi_operand_object *object;341 342	ACPI_FUNCTION_TRACE(ds_method_data_get_value);343 344	/* Validate the object descriptor */345 346	if (!dest_desc) {347		ACPI_ERROR((AE_INFO, "Null object descriptor pointer"));348		return_ACPI_STATUS(AE_BAD_PARAMETER);349	}350 351	/* Get the namespace node for the arg/local */352 353	status = acpi_ds_method_data_get_node(type, index, walk_state, &node);354	if (ACPI_FAILURE(status)) {355		return_ACPI_STATUS(status);356	}357 358	/* Get the object from the node */359 360	object = node->object;361 362	/* Examine the returned object, it must be valid. */363 364	if (!object) {365		/*366		 * Index points to uninitialized object.367		 * This means that either 1) The expected argument was368		 * not passed to the method, or 2) A local variable369		 * was referenced by the method (via the ASL)370		 * before it was initialized. Either case is an error.371		 */372 373		/* If slack enabled, init the local_x/arg_x to an Integer of value zero */374 375		if (acpi_gbl_enable_interpreter_slack) {376			object = acpi_ut_create_integer_object((u64) 0);377			if (!object) {378				return_ACPI_STATUS(AE_NO_MEMORY);379			}380 381			node->object = object;382		}383 384		/* Otherwise, return the error */385 386		else387			switch (type) {388			case ACPI_REFCLASS_ARG:389 390				ACPI_ERROR((AE_INFO,391					    "Uninitialized Arg[%u] at node %p",392					    index, node));393 394				return_ACPI_STATUS(AE_AML_UNINITIALIZED_ARG);395 396			case ACPI_REFCLASS_LOCAL:397				/*398				 * No error message for this case, will be trapped again later to399				 * detect and ignore cases of Store(local_x,local_x)400				 */401				return_ACPI_STATUS(AE_AML_UNINITIALIZED_LOCAL);402 403			default:404 405				ACPI_ERROR((AE_INFO,406					    "Not a Arg/Local opcode: 0x%X",407					    type));408				return_ACPI_STATUS(AE_AML_INTERNAL);409			}410	}411 412	/*413	 * The Index points to an initialized and valid object.414	 * Return an additional reference to the object415	 */416	*dest_desc = object;417	acpi_ut_add_reference(object);418 419	return_ACPI_STATUS(AE_OK);420}421 422/*******************************************************************************423 *424 * FUNCTION:    acpi_ds_method_data_delete_value425 *426 * PARAMETERS:  type                - Either ACPI_REFCLASS_LOCAL or427 *                                    ACPI_REFCLASS_ARG428 *              index               - Which localVar or argument to delete429 *              walk_state          - Current walk state object430 *431 * RETURN:      None432 *433 * DESCRIPTION: Delete the entry at Opcode:Index. Inserts434 *              a null into the stack slot after the object is deleted.435 *436 ******************************************************************************/437 438static void439acpi_ds_method_data_delete_value(u8 type,440				 u32 index, struct acpi_walk_state *walk_state)441{442	acpi_status status;443	struct acpi_namespace_node *node;444	union acpi_operand_object *object;445 446	ACPI_FUNCTION_TRACE(ds_method_data_delete_value);447 448	/* Get the namespace node for the arg/local */449 450	status = acpi_ds_method_data_get_node(type, index, walk_state, &node);451	if (ACPI_FAILURE(status)) {452		return_VOID;453	}454 455	/* Get the associated object */456 457	object = acpi_ns_get_attached_object(node);458 459	/*460	 * Undefine the Arg or Local by setting its descriptor461	 * pointer to NULL. Locals/Args can contain both462	 * ACPI_OPERAND_OBJECTS and ACPI_NAMESPACE_NODEs463	 */464	node->object = NULL;465 466	if ((object) &&467	    (ACPI_GET_DESCRIPTOR_TYPE(object) == ACPI_DESC_TYPE_OPERAND)) {468		/*469		 * There is a valid object.470		 * Decrement the reference count by one to balance the471		 * increment when the object was stored.472		 */473		acpi_ut_remove_reference(object);474	}475 476	return_VOID;477}478 479/*******************************************************************************480 *481 * FUNCTION:    acpi_ds_store_object_to_local482 *483 * PARAMETERS:  type                - Either ACPI_REFCLASS_LOCAL or484 *                                    ACPI_REFCLASS_ARG485 *              index               - Which Local or Arg to set486 *              obj_desc            - Value to be stored487 *              walk_state          - Current walk state488 *489 * RETURN:      Status490 *491 * DESCRIPTION: Store a value in an Arg or Local. The obj_desc is installed492 *              as the new value for the Arg or Local and the reference count493 *              for obj_desc is incremented.494 *495 ******************************************************************************/496 497acpi_status498acpi_ds_store_object_to_local(u8 type,499			      u32 index,500			      union acpi_operand_object *obj_desc,501			      struct acpi_walk_state *walk_state)502{503	acpi_status status;504	struct acpi_namespace_node *node;505	union acpi_operand_object *current_obj_desc;506	union acpi_operand_object *new_obj_desc;507 508	ACPI_FUNCTION_TRACE(ds_store_object_to_local);509	ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Type=%2.2X Index=%u Obj=%p\n",510			  type, index, obj_desc));511 512	/* Parameter validation */513 514	if (!obj_desc) {515		return_ACPI_STATUS(AE_BAD_PARAMETER);516	}517 518	/* Get the namespace node for the arg/local */519 520	status = acpi_ds_method_data_get_node(type, index, walk_state, &node);521	if (ACPI_FAILURE(status)) {522		return_ACPI_STATUS(status);523	}524 525	current_obj_desc = acpi_ns_get_attached_object(node);526	if (current_obj_desc == obj_desc) {527		ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Obj=%p already installed!\n",528				  obj_desc));529		return_ACPI_STATUS(status);530	}531 532	/*533	 * If the reference count on the object is more than one, we must534	 * take a copy of the object before we store. A reference count535	 * of exactly 1 means that the object was just created during the536	 * evaluation of an expression, and we can safely use it since it537	 * is not used anywhere else.538	 */539	new_obj_desc = obj_desc;540	if (obj_desc->common.reference_count > 1) {541		status =542		    acpi_ut_copy_iobject_to_iobject(obj_desc, &new_obj_desc,543						    walk_state);544		if (ACPI_FAILURE(status)) {545			return_ACPI_STATUS(status);546		}547	}548 549	/*550	 * If there is an object already in this slot, we either551	 * have to delete it, or if this is an argument and there552	 * is an object reference stored there, we have to do553	 * an indirect store!554	 */555	if (current_obj_desc) {556		/*557		 * Check for an indirect store if an argument558		 * contains an object reference (stored as an Node).559		 * We don't allow this automatic dereferencing for560		 * locals, since a store to a local should overwrite561		 * anything there, including an object reference.562		 *563		 * If both Arg0 and Local0 contain ref_of (Local4):564		 *565		 * Store (1, Arg0)             - Causes indirect store to local4566		 * Store (1, Local0)           - Stores 1 in local0, overwriting567		 *                                  the reference to local4568		 * Store (1, de_refof (Local0)) - Causes indirect store to local4569		 *570		 * Weird, but true.571		 */572		if (type == ACPI_REFCLASS_ARG) {573			/*574			 * If we have a valid reference object that came from ref_of(),575			 * do the indirect store576			 */577			if ((ACPI_GET_DESCRIPTOR_TYPE(current_obj_desc) ==578			     ACPI_DESC_TYPE_OPERAND) &&579			    (current_obj_desc->common.type ==580			     ACPI_TYPE_LOCAL_REFERENCE) &&581			    (current_obj_desc->reference.class ==582			     ACPI_REFCLASS_REFOF)) {583				ACPI_DEBUG_PRINT((ACPI_DB_EXEC,584						  "Arg (%p) is an ObjRef(Node), storing in node %p\n",585						  new_obj_desc,586						  current_obj_desc));587 588				/*589				 * Store this object to the Node (perform the indirect store)590				 * NOTE: No implicit conversion is performed, as per the ACPI591				 * specification rules on storing to Locals/Args.592				 */593				status =594				    acpi_ex_store_object_to_node(new_obj_desc,595								 current_obj_desc->596								 reference.597								 object,598								 walk_state,599								 ACPI_NO_IMPLICIT_CONVERSION);600 601				/* Remove local reference if we copied the object above */602 603				if (new_obj_desc != obj_desc) {604					acpi_ut_remove_reference(new_obj_desc);605				}606 607				return_ACPI_STATUS(status);608			}609		}610 611		/* Delete the existing object before storing the new one */612 613		acpi_ds_method_data_delete_value(type, index, walk_state);614	}615 616	/*617	 * Install the Obj descriptor (*new_obj_desc) into618	 * the descriptor for the Arg or Local.619	 * (increments the object reference count by one)620	 */621	status =622	    acpi_ds_method_data_set_value(type, index, new_obj_desc,623					  walk_state);624 625	/* Remove local reference if we copied the object above */626 627	if (new_obj_desc != obj_desc) {628		acpi_ut_remove_reference(new_obj_desc);629	}630 631	return_ACPI_STATUS(status);632}633 634#ifdef ACPI_OBSOLETE_FUNCTIONS635/*******************************************************************************636 *637 * FUNCTION:    acpi_ds_method_data_get_type638 *639 * PARAMETERS:  opcode              - Either AML_FIRST LOCAL_OP or640 *                                    AML_FIRST_ARG_OP641 *              index               - Which Local or Arg whose type to get642 *              walk_state          - Current walk state object643 *644 * RETURN:      Data type of current value of the selected Arg or Local645 *646 * DESCRIPTION: Get the type of the object stored in the Local or Arg647 *648 ******************************************************************************/649 650acpi_object_type651acpi_ds_method_data_get_type(u16 opcode,652			     u32 index, struct acpi_walk_state *walk_state)653{654	acpi_status status;655	struct acpi_namespace_node *node;656	union acpi_operand_object *object;657 658	ACPI_FUNCTION_TRACE(ds_method_data_get_type);659 660	/* Get the namespace node for the arg/local */661 662	status = acpi_ds_method_data_get_node(opcode, index, walk_state, &node);663	if (ACPI_FAILURE(status)) {664		return_VALUE((ACPI_TYPE_NOT_FOUND));665	}666 667	/* Get the object */668 669	object = acpi_ns_get_attached_object(node);670	if (!object) {671 672		/* Uninitialized local/arg, return TYPE_ANY */673 674		return_VALUE(ACPI_TYPE_ANY);675	}676 677	/* Get the object type */678 679	return_VALUE(object->type);680}681#endif682