162306a36Sopenharmony_ci// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
262306a36Sopenharmony_ci/*******************************************************************************
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * Module Name: dsmthdat - control method arguments and local variables
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci ******************************************************************************/
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include <acpi/acpi.h>
962306a36Sopenharmony_ci#include "accommon.h"
1062306a36Sopenharmony_ci#include "acdispat.h"
1162306a36Sopenharmony_ci#include "acnamesp.h"
1262306a36Sopenharmony_ci#include "acinterp.h"
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci#define _COMPONENT          ACPI_DISPATCHER
1562306a36Sopenharmony_ciACPI_MODULE_NAME("dsmthdat")
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci/* Local prototypes */
1862306a36Sopenharmony_cistatic void
1962306a36Sopenharmony_ciacpi_ds_method_data_delete_value(u8 type,
2062306a36Sopenharmony_ci				 u32 index, struct acpi_walk_state *walk_state);
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_cistatic acpi_status
2362306a36Sopenharmony_ciacpi_ds_method_data_set_value(u8 type,
2462306a36Sopenharmony_ci			      u32 index,
2562306a36Sopenharmony_ci			      union acpi_operand_object *object,
2662306a36Sopenharmony_ci			      struct acpi_walk_state *walk_state);
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci#ifdef ACPI_OBSOLETE_FUNCTIONS
2962306a36Sopenharmony_ciacpi_object_type
3062306a36Sopenharmony_ciacpi_ds_method_data_get_type(u16 opcode,
3162306a36Sopenharmony_ci			     u32 index, struct acpi_walk_state *walk_state);
3262306a36Sopenharmony_ci#endif
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci/*******************************************************************************
3562306a36Sopenharmony_ci *
3662306a36Sopenharmony_ci * FUNCTION:    acpi_ds_method_data_init
3762306a36Sopenharmony_ci *
3862306a36Sopenharmony_ci * PARAMETERS:  walk_state          - Current walk state object
3962306a36Sopenharmony_ci *
4062306a36Sopenharmony_ci * RETURN:      Status
4162306a36Sopenharmony_ci *
4262306a36Sopenharmony_ci * DESCRIPTION: Initialize the data structures that hold the method's arguments
4362306a36Sopenharmony_ci *              and locals. The data struct is an array of namespace nodes for
4462306a36Sopenharmony_ci *              each - this allows ref_of and de_ref_of to work properly for these
4562306a36Sopenharmony_ci *              special data types.
4662306a36Sopenharmony_ci *
4762306a36Sopenharmony_ci * NOTES:       walk_state fields are initialized to zero by the
4862306a36Sopenharmony_ci *              ACPI_ALLOCATE_ZEROED().
4962306a36Sopenharmony_ci *
5062306a36Sopenharmony_ci *              A pseudo-Namespace Node is assigned to each argument and local
5162306a36Sopenharmony_ci *              so that ref_of() can return a pointer to the Node.
5262306a36Sopenharmony_ci *
5362306a36Sopenharmony_ci ******************************************************************************/
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_civoid acpi_ds_method_data_init(struct acpi_walk_state *walk_state)
5662306a36Sopenharmony_ci{
5762306a36Sopenharmony_ci	u32 i;
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci	ACPI_FUNCTION_TRACE(ds_method_data_init);
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci	/* Init the method arguments */
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci	for (i = 0; i < ACPI_METHOD_NUM_ARGS; i++) {
6462306a36Sopenharmony_ci		ACPI_MOVE_32_TO_32(&walk_state->arguments[i].name,
6562306a36Sopenharmony_ci				   NAMEOF_ARG_NTE);
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci		walk_state->arguments[i].name.integer |= (i << 24);
6862306a36Sopenharmony_ci		walk_state->arguments[i].descriptor_type = ACPI_DESC_TYPE_NAMED;
6962306a36Sopenharmony_ci		walk_state->arguments[i].type = ACPI_TYPE_ANY;
7062306a36Sopenharmony_ci		walk_state->arguments[i].flags = ANOBJ_METHOD_ARG;
7162306a36Sopenharmony_ci	}
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci	/* Init the method locals */
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci	for (i = 0; i < ACPI_METHOD_NUM_LOCALS; i++) {
7662306a36Sopenharmony_ci		ACPI_MOVE_32_TO_32(&walk_state->local_variables[i].name,
7762306a36Sopenharmony_ci				   NAMEOF_LOCAL_NTE);
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci		walk_state->local_variables[i].name.integer |= (i << 24);
8062306a36Sopenharmony_ci		walk_state->local_variables[i].descriptor_type =
8162306a36Sopenharmony_ci		    ACPI_DESC_TYPE_NAMED;
8262306a36Sopenharmony_ci		walk_state->local_variables[i].type = ACPI_TYPE_ANY;
8362306a36Sopenharmony_ci		walk_state->local_variables[i].flags = ANOBJ_METHOD_LOCAL;
8462306a36Sopenharmony_ci	}
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci	return_VOID;
8762306a36Sopenharmony_ci}
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci/*******************************************************************************
9062306a36Sopenharmony_ci *
9162306a36Sopenharmony_ci * FUNCTION:    acpi_ds_method_data_delete_all
9262306a36Sopenharmony_ci *
9362306a36Sopenharmony_ci * PARAMETERS:  walk_state          - Current walk state object
9462306a36Sopenharmony_ci *
9562306a36Sopenharmony_ci * RETURN:      None
9662306a36Sopenharmony_ci *
9762306a36Sopenharmony_ci * DESCRIPTION: Delete method locals and arguments. Arguments are only
9862306a36Sopenharmony_ci *              deleted if this method was called from another method.
9962306a36Sopenharmony_ci *
10062306a36Sopenharmony_ci ******************************************************************************/
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_civoid acpi_ds_method_data_delete_all(struct acpi_walk_state *walk_state)
10362306a36Sopenharmony_ci{
10462306a36Sopenharmony_ci	u32 index;
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci	ACPI_FUNCTION_TRACE(ds_method_data_delete_all);
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci	/* Detach the locals */
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci	for (index = 0; index < ACPI_METHOD_NUM_LOCALS; index++) {
11162306a36Sopenharmony_ci		if (walk_state->local_variables[index].object) {
11262306a36Sopenharmony_ci			ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Deleting Local%u=%p\n",
11362306a36Sopenharmony_ci					  index,
11462306a36Sopenharmony_ci					  walk_state->local_variables[index].
11562306a36Sopenharmony_ci					  object));
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci			/* Detach object (if present) and remove a reference */
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci			acpi_ns_detach_object(&walk_state->
12062306a36Sopenharmony_ci					      local_variables[index]);
12162306a36Sopenharmony_ci		}
12262306a36Sopenharmony_ci	}
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci	/* Detach the arguments */
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci	for (index = 0; index < ACPI_METHOD_NUM_ARGS; index++) {
12762306a36Sopenharmony_ci		if (walk_state->arguments[index].object) {
12862306a36Sopenharmony_ci			ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Deleting Arg%u=%p\n",
12962306a36Sopenharmony_ci					  index,
13062306a36Sopenharmony_ci					  walk_state->arguments[index].object));
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci			/* Detach object (if present) and remove a reference */
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ci			acpi_ns_detach_object(&walk_state->arguments[index]);
13562306a36Sopenharmony_ci		}
13662306a36Sopenharmony_ci	}
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci	return_VOID;
13962306a36Sopenharmony_ci}
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci/*******************************************************************************
14262306a36Sopenharmony_ci *
14362306a36Sopenharmony_ci * FUNCTION:    acpi_ds_method_data_init_args
14462306a36Sopenharmony_ci *
14562306a36Sopenharmony_ci * PARAMETERS:  *params         - Pointer to a parameter list for the method
14662306a36Sopenharmony_ci *              max_param_count - The arg count for this method
14762306a36Sopenharmony_ci *              walk_state      - Current walk state object
14862306a36Sopenharmony_ci *
14962306a36Sopenharmony_ci * RETURN:      Status
15062306a36Sopenharmony_ci *
15162306a36Sopenharmony_ci * DESCRIPTION: Initialize arguments for a method. The parameter list is a list
15262306a36Sopenharmony_ci *              of ACPI operand objects, either null terminated or whose length
15362306a36Sopenharmony_ci *              is defined by max_param_count.
15462306a36Sopenharmony_ci *
15562306a36Sopenharmony_ci ******************************************************************************/
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ciacpi_status
15862306a36Sopenharmony_ciacpi_ds_method_data_init_args(union acpi_operand_object **params,
15962306a36Sopenharmony_ci			      u32 max_param_count,
16062306a36Sopenharmony_ci			      struct acpi_walk_state *walk_state)
16162306a36Sopenharmony_ci{
16262306a36Sopenharmony_ci	acpi_status status;
16362306a36Sopenharmony_ci	u32 index = 0;
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci	ACPI_FUNCTION_TRACE_PTR(ds_method_data_init_args, params);
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci	if (!params) {
16862306a36Sopenharmony_ci		ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
16962306a36Sopenharmony_ci				  "No parameter list passed to method\n"));
17062306a36Sopenharmony_ci		return_ACPI_STATUS(AE_OK);
17162306a36Sopenharmony_ci	}
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci	/* Copy passed parameters into the new method stack frame */
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci	while ((index < ACPI_METHOD_NUM_ARGS) &&
17662306a36Sopenharmony_ci	       (index < max_param_count) && params[index]) {
17762306a36Sopenharmony_ci		/*
17862306a36Sopenharmony_ci		 * A valid parameter.
17962306a36Sopenharmony_ci		 * Store the argument in the method/walk descriptor.
18062306a36Sopenharmony_ci		 * Do not copy the arg in order to implement call by reference
18162306a36Sopenharmony_ci		 */
18262306a36Sopenharmony_ci		status =
18362306a36Sopenharmony_ci		    acpi_ds_method_data_set_value(ACPI_REFCLASS_ARG, index,
18462306a36Sopenharmony_ci						  params[index], walk_state);
18562306a36Sopenharmony_ci		if (ACPI_FAILURE(status)) {
18662306a36Sopenharmony_ci			return_ACPI_STATUS(status);
18762306a36Sopenharmony_ci		}
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci		index++;
19062306a36Sopenharmony_ci	}
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci	ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "%u args passed to method\n", index));
19362306a36Sopenharmony_ci	return_ACPI_STATUS(AE_OK);
19462306a36Sopenharmony_ci}
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci/*******************************************************************************
19762306a36Sopenharmony_ci *
19862306a36Sopenharmony_ci * FUNCTION:    acpi_ds_method_data_get_node
19962306a36Sopenharmony_ci *
20062306a36Sopenharmony_ci * PARAMETERS:  type                - Either ACPI_REFCLASS_LOCAL or
20162306a36Sopenharmony_ci *                                    ACPI_REFCLASS_ARG
20262306a36Sopenharmony_ci *              index               - Which Local or Arg whose type to get
20362306a36Sopenharmony_ci *              walk_state          - Current walk state object
20462306a36Sopenharmony_ci *              node                - Where the node is returned.
20562306a36Sopenharmony_ci *
20662306a36Sopenharmony_ci * RETURN:      Status and node
20762306a36Sopenharmony_ci *
20862306a36Sopenharmony_ci * DESCRIPTION: Get the Node associated with a local or arg.
20962306a36Sopenharmony_ci *
21062306a36Sopenharmony_ci ******************************************************************************/
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ciacpi_status
21362306a36Sopenharmony_ciacpi_ds_method_data_get_node(u8 type,
21462306a36Sopenharmony_ci			     u32 index,
21562306a36Sopenharmony_ci			     struct acpi_walk_state *walk_state,
21662306a36Sopenharmony_ci			     struct acpi_namespace_node **node)
21762306a36Sopenharmony_ci{
21862306a36Sopenharmony_ci	ACPI_FUNCTION_TRACE(ds_method_data_get_node);
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci	/*
22162306a36Sopenharmony_ci	 * Method Locals and Arguments are supported
22262306a36Sopenharmony_ci	 */
22362306a36Sopenharmony_ci	switch (type) {
22462306a36Sopenharmony_ci	case ACPI_REFCLASS_LOCAL:
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ci		if (index > ACPI_METHOD_MAX_LOCAL) {
22762306a36Sopenharmony_ci			ACPI_ERROR((AE_INFO,
22862306a36Sopenharmony_ci				    "Local index %u is invalid (max %u)",
22962306a36Sopenharmony_ci				    index, ACPI_METHOD_MAX_LOCAL));
23062306a36Sopenharmony_ci			return_ACPI_STATUS(AE_AML_INVALID_INDEX);
23162306a36Sopenharmony_ci		}
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ci		/* Return a pointer to the pseudo-node */
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_ci		*node = &walk_state->local_variables[index];
23662306a36Sopenharmony_ci		break;
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ci	case ACPI_REFCLASS_ARG:
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_ci		if (index > ACPI_METHOD_MAX_ARG) {
24162306a36Sopenharmony_ci			ACPI_ERROR((AE_INFO,
24262306a36Sopenharmony_ci				    "Arg index %u is invalid (max %u)",
24362306a36Sopenharmony_ci				    index, ACPI_METHOD_MAX_ARG));
24462306a36Sopenharmony_ci			return_ACPI_STATUS(AE_AML_INVALID_INDEX);
24562306a36Sopenharmony_ci		}
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ci		/* Return a pointer to the pseudo-node */
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci		*node = &walk_state->arguments[index];
25062306a36Sopenharmony_ci		break;
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_ci	default:
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ci		ACPI_ERROR((AE_INFO, "Type %u is invalid", type));
25562306a36Sopenharmony_ci		return_ACPI_STATUS(AE_TYPE);
25662306a36Sopenharmony_ci	}
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_ci	return_ACPI_STATUS(AE_OK);
25962306a36Sopenharmony_ci}
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ci/*******************************************************************************
26262306a36Sopenharmony_ci *
26362306a36Sopenharmony_ci * FUNCTION:    acpi_ds_method_data_set_value
26462306a36Sopenharmony_ci *
26562306a36Sopenharmony_ci * PARAMETERS:  type                - Either ACPI_REFCLASS_LOCAL or
26662306a36Sopenharmony_ci *                                    ACPI_REFCLASS_ARG
26762306a36Sopenharmony_ci *              index               - Which Local or Arg to get
26862306a36Sopenharmony_ci *              object              - Object to be inserted into the stack entry
26962306a36Sopenharmony_ci *              walk_state          - Current walk state object
27062306a36Sopenharmony_ci *
27162306a36Sopenharmony_ci * RETURN:      Status
27262306a36Sopenharmony_ci *
27362306a36Sopenharmony_ci * DESCRIPTION: Insert an object onto the method stack at entry Opcode:Index.
27462306a36Sopenharmony_ci *              Note: There is no "implicit conversion" for locals.
27562306a36Sopenharmony_ci *
27662306a36Sopenharmony_ci ******************************************************************************/
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_cistatic acpi_status
27962306a36Sopenharmony_ciacpi_ds_method_data_set_value(u8 type,
28062306a36Sopenharmony_ci			      u32 index,
28162306a36Sopenharmony_ci			      union acpi_operand_object *object,
28262306a36Sopenharmony_ci			      struct acpi_walk_state *walk_state)
28362306a36Sopenharmony_ci{
28462306a36Sopenharmony_ci	acpi_status status;
28562306a36Sopenharmony_ci	struct acpi_namespace_node *node;
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_ci	ACPI_FUNCTION_TRACE(ds_method_data_set_value);
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci	ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
29062306a36Sopenharmony_ci			  "NewObj %p Type %2.2X, Refs=%u [%s]\n", object,
29162306a36Sopenharmony_ci			  type, object->common.reference_count,
29262306a36Sopenharmony_ci			  acpi_ut_get_type_name(object->common.type)));
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_ci	/* Get the namespace node for the arg/local */
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_ci	status = acpi_ds_method_data_get_node(type, index, walk_state, &node);
29762306a36Sopenharmony_ci	if (ACPI_FAILURE(status)) {
29862306a36Sopenharmony_ci		return_ACPI_STATUS(status);
29962306a36Sopenharmony_ci	}
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ci	/*
30262306a36Sopenharmony_ci	 * Increment ref count so object can't be deleted while installed.
30362306a36Sopenharmony_ci	 * NOTE: We do not copy the object in order to preserve the call by
30462306a36Sopenharmony_ci	 * reference semantics of ACPI Control Method invocation.
30562306a36Sopenharmony_ci	 * (See ACPI Specification 2.0C)
30662306a36Sopenharmony_ci	 */
30762306a36Sopenharmony_ci	acpi_ut_add_reference(object);
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ci	/* Install the object */
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ci	node->object = object;
31262306a36Sopenharmony_ci	return_ACPI_STATUS(status);
31362306a36Sopenharmony_ci}
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci/*******************************************************************************
31662306a36Sopenharmony_ci *
31762306a36Sopenharmony_ci * FUNCTION:    acpi_ds_method_data_get_value
31862306a36Sopenharmony_ci *
31962306a36Sopenharmony_ci * PARAMETERS:  type                - Either ACPI_REFCLASS_LOCAL or
32062306a36Sopenharmony_ci *                                    ACPI_REFCLASS_ARG
32162306a36Sopenharmony_ci *              index               - Which localVar or argument to get
32262306a36Sopenharmony_ci *              walk_state          - Current walk state object
32362306a36Sopenharmony_ci *              dest_desc           - Where Arg or Local value is returned
32462306a36Sopenharmony_ci *
32562306a36Sopenharmony_ci * RETURN:      Status
32662306a36Sopenharmony_ci *
32762306a36Sopenharmony_ci * DESCRIPTION: Retrieve value of selected Arg or Local for this method
32862306a36Sopenharmony_ci *              Used only in acpi_ex_resolve_to_value().
32962306a36Sopenharmony_ci *
33062306a36Sopenharmony_ci ******************************************************************************/
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ciacpi_status
33362306a36Sopenharmony_ciacpi_ds_method_data_get_value(u8 type,
33462306a36Sopenharmony_ci			      u32 index,
33562306a36Sopenharmony_ci			      struct acpi_walk_state *walk_state,
33662306a36Sopenharmony_ci			      union acpi_operand_object **dest_desc)
33762306a36Sopenharmony_ci{
33862306a36Sopenharmony_ci	acpi_status status;
33962306a36Sopenharmony_ci	struct acpi_namespace_node *node;
34062306a36Sopenharmony_ci	union acpi_operand_object *object;
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_ci	ACPI_FUNCTION_TRACE(ds_method_data_get_value);
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_ci	/* Validate the object descriptor */
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_ci	if (!dest_desc) {
34762306a36Sopenharmony_ci		ACPI_ERROR((AE_INFO, "Null object descriptor pointer"));
34862306a36Sopenharmony_ci		return_ACPI_STATUS(AE_BAD_PARAMETER);
34962306a36Sopenharmony_ci	}
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_ci	/* Get the namespace node for the arg/local */
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ci	status = acpi_ds_method_data_get_node(type, index, walk_state, &node);
35462306a36Sopenharmony_ci	if (ACPI_FAILURE(status)) {
35562306a36Sopenharmony_ci		return_ACPI_STATUS(status);
35662306a36Sopenharmony_ci	}
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_ci	/* Get the object from the node */
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_ci	object = node->object;
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_ci	/* Examine the returned object, it must be valid. */
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ci	if (!object) {
36562306a36Sopenharmony_ci		/*
36662306a36Sopenharmony_ci		 * Index points to uninitialized object.
36762306a36Sopenharmony_ci		 * This means that either 1) The expected argument was
36862306a36Sopenharmony_ci		 * not passed to the method, or 2) A local variable
36962306a36Sopenharmony_ci		 * was referenced by the method (via the ASL)
37062306a36Sopenharmony_ci		 * before it was initialized. Either case is an error.
37162306a36Sopenharmony_ci		 */
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_ci		/* If slack enabled, init the local_x/arg_x to an Integer of value zero */
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_ci		if (acpi_gbl_enable_interpreter_slack) {
37662306a36Sopenharmony_ci			object = acpi_ut_create_integer_object((u64) 0);
37762306a36Sopenharmony_ci			if (!object) {
37862306a36Sopenharmony_ci				return_ACPI_STATUS(AE_NO_MEMORY);
37962306a36Sopenharmony_ci			}
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_ci			node->object = object;
38262306a36Sopenharmony_ci		}
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_ci		/* Otherwise, return the error */
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_ci		else
38762306a36Sopenharmony_ci			switch (type) {
38862306a36Sopenharmony_ci			case ACPI_REFCLASS_ARG:
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_ci				ACPI_ERROR((AE_INFO,
39162306a36Sopenharmony_ci					    "Uninitialized Arg[%u] at node %p",
39262306a36Sopenharmony_ci					    index, node));
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_ci				return_ACPI_STATUS(AE_AML_UNINITIALIZED_ARG);
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci			case ACPI_REFCLASS_LOCAL:
39762306a36Sopenharmony_ci				/*
39862306a36Sopenharmony_ci				 * No error message for this case, will be trapped again later to
39962306a36Sopenharmony_ci				 * detect and ignore cases of Store(local_x,local_x)
40062306a36Sopenharmony_ci				 */
40162306a36Sopenharmony_ci				return_ACPI_STATUS(AE_AML_UNINITIALIZED_LOCAL);
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_ci			default:
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ci				ACPI_ERROR((AE_INFO,
40662306a36Sopenharmony_ci					    "Not a Arg/Local opcode: 0x%X",
40762306a36Sopenharmony_ci					    type));
40862306a36Sopenharmony_ci				return_ACPI_STATUS(AE_AML_INTERNAL);
40962306a36Sopenharmony_ci			}
41062306a36Sopenharmony_ci	}
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_ci	/*
41362306a36Sopenharmony_ci	 * The Index points to an initialized and valid object.
41462306a36Sopenharmony_ci	 * Return an additional reference to the object
41562306a36Sopenharmony_ci	 */
41662306a36Sopenharmony_ci	*dest_desc = object;
41762306a36Sopenharmony_ci	acpi_ut_add_reference(object);
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_ci	return_ACPI_STATUS(AE_OK);
42062306a36Sopenharmony_ci}
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_ci/*******************************************************************************
42362306a36Sopenharmony_ci *
42462306a36Sopenharmony_ci * FUNCTION:    acpi_ds_method_data_delete_value
42562306a36Sopenharmony_ci *
42662306a36Sopenharmony_ci * PARAMETERS:  type                - Either ACPI_REFCLASS_LOCAL or
42762306a36Sopenharmony_ci *                                    ACPI_REFCLASS_ARG
42862306a36Sopenharmony_ci *              index               - Which localVar or argument to delete
42962306a36Sopenharmony_ci *              walk_state          - Current walk state object
43062306a36Sopenharmony_ci *
43162306a36Sopenharmony_ci * RETURN:      None
43262306a36Sopenharmony_ci *
43362306a36Sopenharmony_ci * DESCRIPTION: Delete the entry at Opcode:Index. Inserts
43462306a36Sopenharmony_ci *              a null into the stack slot after the object is deleted.
43562306a36Sopenharmony_ci *
43662306a36Sopenharmony_ci ******************************************************************************/
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_cistatic void
43962306a36Sopenharmony_ciacpi_ds_method_data_delete_value(u8 type,
44062306a36Sopenharmony_ci				 u32 index, struct acpi_walk_state *walk_state)
44162306a36Sopenharmony_ci{
44262306a36Sopenharmony_ci	acpi_status status;
44362306a36Sopenharmony_ci	struct acpi_namespace_node *node;
44462306a36Sopenharmony_ci	union acpi_operand_object *object;
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_ci	ACPI_FUNCTION_TRACE(ds_method_data_delete_value);
44762306a36Sopenharmony_ci
44862306a36Sopenharmony_ci	/* Get the namespace node for the arg/local */
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_ci	status = acpi_ds_method_data_get_node(type, index, walk_state, &node);
45162306a36Sopenharmony_ci	if (ACPI_FAILURE(status)) {
45262306a36Sopenharmony_ci		return_VOID;
45362306a36Sopenharmony_ci	}
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_ci	/* Get the associated object */
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_ci	object = acpi_ns_get_attached_object(node);
45862306a36Sopenharmony_ci
45962306a36Sopenharmony_ci	/*
46062306a36Sopenharmony_ci	 * Undefine the Arg or Local by setting its descriptor
46162306a36Sopenharmony_ci	 * pointer to NULL. Locals/Args can contain both
46262306a36Sopenharmony_ci	 * ACPI_OPERAND_OBJECTS and ACPI_NAMESPACE_NODEs
46362306a36Sopenharmony_ci	 */
46462306a36Sopenharmony_ci	node->object = NULL;
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_ci	if ((object) &&
46762306a36Sopenharmony_ci	    (ACPI_GET_DESCRIPTOR_TYPE(object) == ACPI_DESC_TYPE_OPERAND)) {
46862306a36Sopenharmony_ci		/*
46962306a36Sopenharmony_ci		 * There is a valid object.
47062306a36Sopenharmony_ci		 * Decrement the reference count by one to balance the
47162306a36Sopenharmony_ci		 * increment when the object was stored.
47262306a36Sopenharmony_ci		 */
47362306a36Sopenharmony_ci		acpi_ut_remove_reference(object);
47462306a36Sopenharmony_ci	}
47562306a36Sopenharmony_ci
47662306a36Sopenharmony_ci	return_VOID;
47762306a36Sopenharmony_ci}
47862306a36Sopenharmony_ci
47962306a36Sopenharmony_ci/*******************************************************************************
48062306a36Sopenharmony_ci *
48162306a36Sopenharmony_ci * FUNCTION:    acpi_ds_store_object_to_local
48262306a36Sopenharmony_ci *
48362306a36Sopenharmony_ci * PARAMETERS:  type                - Either ACPI_REFCLASS_LOCAL or
48462306a36Sopenharmony_ci *                                    ACPI_REFCLASS_ARG
48562306a36Sopenharmony_ci *              index               - Which Local or Arg to set
48662306a36Sopenharmony_ci *              obj_desc            - Value to be stored
48762306a36Sopenharmony_ci *              walk_state          - Current walk state
48862306a36Sopenharmony_ci *
48962306a36Sopenharmony_ci * RETURN:      Status
49062306a36Sopenharmony_ci *
49162306a36Sopenharmony_ci * DESCRIPTION: Store a value in an Arg or Local. The obj_desc is installed
49262306a36Sopenharmony_ci *              as the new value for the Arg or Local and the reference count
49362306a36Sopenharmony_ci *              for obj_desc is incremented.
49462306a36Sopenharmony_ci *
49562306a36Sopenharmony_ci ******************************************************************************/
49662306a36Sopenharmony_ci
49762306a36Sopenharmony_ciacpi_status
49862306a36Sopenharmony_ciacpi_ds_store_object_to_local(u8 type,
49962306a36Sopenharmony_ci			      u32 index,
50062306a36Sopenharmony_ci			      union acpi_operand_object *obj_desc,
50162306a36Sopenharmony_ci			      struct acpi_walk_state *walk_state)
50262306a36Sopenharmony_ci{
50362306a36Sopenharmony_ci	acpi_status status;
50462306a36Sopenharmony_ci	struct acpi_namespace_node *node;
50562306a36Sopenharmony_ci	union acpi_operand_object *current_obj_desc;
50662306a36Sopenharmony_ci	union acpi_operand_object *new_obj_desc;
50762306a36Sopenharmony_ci
50862306a36Sopenharmony_ci	ACPI_FUNCTION_TRACE(ds_store_object_to_local);
50962306a36Sopenharmony_ci	ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Type=%2.2X Index=%u Obj=%p\n",
51062306a36Sopenharmony_ci			  type, index, obj_desc));
51162306a36Sopenharmony_ci
51262306a36Sopenharmony_ci	/* Parameter validation */
51362306a36Sopenharmony_ci
51462306a36Sopenharmony_ci	if (!obj_desc) {
51562306a36Sopenharmony_ci		return_ACPI_STATUS(AE_BAD_PARAMETER);
51662306a36Sopenharmony_ci	}
51762306a36Sopenharmony_ci
51862306a36Sopenharmony_ci	/* Get the namespace node for the arg/local */
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_ci	status = acpi_ds_method_data_get_node(type, index, walk_state, &node);
52162306a36Sopenharmony_ci	if (ACPI_FAILURE(status)) {
52262306a36Sopenharmony_ci		return_ACPI_STATUS(status);
52362306a36Sopenharmony_ci	}
52462306a36Sopenharmony_ci
52562306a36Sopenharmony_ci	current_obj_desc = acpi_ns_get_attached_object(node);
52662306a36Sopenharmony_ci	if (current_obj_desc == obj_desc) {
52762306a36Sopenharmony_ci		ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Obj=%p already installed!\n",
52862306a36Sopenharmony_ci				  obj_desc));
52962306a36Sopenharmony_ci		return_ACPI_STATUS(status);
53062306a36Sopenharmony_ci	}
53162306a36Sopenharmony_ci
53262306a36Sopenharmony_ci	/*
53362306a36Sopenharmony_ci	 * If the reference count on the object is more than one, we must
53462306a36Sopenharmony_ci	 * take a copy of the object before we store. A reference count
53562306a36Sopenharmony_ci	 * of exactly 1 means that the object was just created during the
53662306a36Sopenharmony_ci	 * evaluation of an expression, and we can safely use it since it
53762306a36Sopenharmony_ci	 * is not used anywhere else.
53862306a36Sopenharmony_ci	 */
53962306a36Sopenharmony_ci	new_obj_desc = obj_desc;
54062306a36Sopenharmony_ci	if (obj_desc->common.reference_count > 1) {
54162306a36Sopenharmony_ci		status =
54262306a36Sopenharmony_ci		    acpi_ut_copy_iobject_to_iobject(obj_desc, &new_obj_desc,
54362306a36Sopenharmony_ci						    walk_state);
54462306a36Sopenharmony_ci		if (ACPI_FAILURE(status)) {
54562306a36Sopenharmony_ci			return_ACPI_STATUS(status);
54662306a36Sopenharmony_ci		}
54762306a36Sopenharmony_ci	}
54862306a36Sopenharmony_ci
54962306a36Sopenharmony_ci	/*
55062306a36Sopenharmony_ci	 * If there is an object already in this slot, we either
55162306a36Sopenharmony_ci	 * have to delete it, or if this is an argument and there
55262306a36Sopenharmony_ci	 * is an object reference stored there, we have to do
55362306a36Sopenharmony_ci	 * an indirect store!
55462306a36Sopenharmony_ci	 */
55562306a36Sopenharmony_ci	if (current_obj_desc) {
55662306a36Sopenharmony_ci		/*
55762306a36Sopenharmony_ci		 * Check for an indirect store if an argument
55862306a36Sopenharmony_ci		 * contains an object reference (stored as an Node).
55962306a36Sopenharmony_ci		 * We don't allow this automatic dereferencing for
56062306a36Sopenharmony_ci		 * locals, since a store to a local should overwrite
56162306a36Sopenharmony_ci		 * anything there, including an object reference.
56262306a36Sopenharmony_ci		 *
56362306a36Sopenharmony_ci		 * If both Arg0 and Local0 contain ref_of (Local4):
56462306a36Sopenharmony_ci		 *
56562306a36Sopenharmony_ci		 * Store (1, Arg0)             - Causes indirect store to local4
56662306a36Sopenharmony_ci		 * Store (1, Local0)           - Stores 1 in local0, overwriting
56762306a36Sopenharmony_ci		 *                                  the reference to local4
56862306a36Sopenharmony_ci		 * Store (1, de_refof (Local0)) - Causes indirect store to local4
56962306a36Sopenharmony_ci		 *
57062306a36Sopenharmony_ci		 * Weird, but true.
57162306a36Sopenharmony_ci		 */
57262306a36Sopenharmony_ci		if (type == ACPI_REFCLASS_ARG) {
57362306a36Sopenharmony_ci			/*
57462306a36Sopenharmony_ci			 * If we have a valid reference object that came from ref_of(),
57562306a36Sopenharmony_ci			 * do the indirect store
57662306a36Sopenharmony_ci			 */
57762306a36Sopenharmony_ci			if ((ACPI_GET_DESCRIPTOR_TYPE(current_obj_desc) ==
57862306a36Sopenharmony_ci			     ACPI_DESC_TYPE_OPERAND) &&
57962306a36Sopenharmony_ci			    (current_obj_desc->common.type ==
58062306a36Sopenharmony_ci			     ACPI_TYPE_LOCAL_REFERENCE) &&
58162306a36Sopenharmony_ci			    (current_obj_desc->reference.class ==
58262306a36Sopenharmony_ci			     ACPI_REFCLASS_REFOF)) {
58362306a36Sopenharmony_ci				ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
58462306a36Sopenharmony_ci						  "Arg (%p) is an ObjRef(Node), storing in node %p\n",
58562306a36Sopenharmony_ci						  new_obj_desc,
58662306a36Sopenharmony_ci						  current_obj_desc));
58762306a36Sopenharmony_ci
58862306a36Sopenharmony_ci				/*
58962306a36Sopenharmony_ci				 * Store this object to the Node (perform the indirect store)
59062306a36Sopenharmony_ci				 * NOTE: No implicit conversion is performed, as per the ACPI
59162306a36Sopenharmony_ci				 * specification rules on storing to Locals/Args.
59262306a36Sopenharmony_ci				 */
59362306a36Sopenharmony_ci				status =
59462306a36Sopenharmony_ci				    acpi_ex_store_object_to_node(new_obj_desc,
59562306a36Sopenharmony_ci								 current_obj_desc->
59662306a36Sopenharmony_ci								 reference.
59762306a36Sopenharmony_ci								 object,
59862306a36Sopenharmony_ci								 walk_state,
59962306a36Sopenharmony_ci								 ACPI_NO_IMPLICIT_CONVERSION);
60062306a36Sopenharmony_ci
60162306a36Sopenharmony_ci				/* Remove local reference if we copied the object above */
60262306a36Sopenharmony_ci
60362306a36Sopenharmony_ci				if (new_obj_desc != obj_desc) {
60462306a36Sopenharmony_ci					acpi_ut_remove_reference(new_obj_desc);
60562306a36Sopenharmony_ci				}
60662306a36Sopenharmony_ci
60762306a36Sopenharmony_ci				return_ACPI_STATUS(status);
60862306a36Sopenharmony_ci			}
60962306a36Sopenharmony_ci		}
61062306a36Sopenharmony_ci
61162306a36Sopenharmony_ci		/* Delete the existing object before storing the new one */
61262306a36Sopenharmony_ci
61362306a36Sopenharmony_ci		acpi_ds_method_data_delete_value(type, index, walk_state);
61462306a36Sopenharmony_ci	}
61562306a36Sopenharmony_ci
61662306a36Sopenharmony_ci	/*
61762306a36Sopenharmony_ci	 * Install the Obj descriptor (*new_obj_desc) into
61862306a36Sopenharmony_ci	 * the descriptor for the Arg or Local.
61962306a36Sopenharmony_ci	 * (increments the object reference count by one)
62062306a36Sopenharmony_ci	 */
62162306a36Sopenharmony_ci	status =
62262306a36Sopenharmony_ci	    acpi_ds_method_data_set_value(type, index, new_obj_desc,
62362306a36Sopenharmony_ci					  walk_state);
62462306a36Sopenharmony_ci
62562306a36Sopenharmony_ci	/* Remove local reference if we copied the object above */
62662306a36Sopenharmony_ci
62762306a36Sopenharmony_ci	if (new_obj_desc != obj_desc) {
62862306a36Sopenharmony_ci		acpi_ut_remove_reference(new_obj_desc);
62962306a36Sopenharmony_ci	}
63062306a36Sopenharmony_ci
63162306a36Sopenharmony_ci	return_ACPI_STATUS(status);
63262306a36Sopenharmony_ci}
63362306a36Sopenharmony_ci
63462306a36Sopenharmony_ci#ifdef ACPI_OBSOLETE_FUNCTIONS
63562306a36Sopenharmony_ci/*******************************************************************************
63662306a36Sopenharmony_ci *
63762306a36Sopenharmony_ci * FUNCTION:    acpi_ds_method_data_get_type
63862306a36Sopenharmony_ci *
63962306a36Sopenharmony_ci * PARAMETERS:  opcode              - Either AML_FIRST LOCAL_OP or
64062306a36Sopenharmony_ci *                                    AML_FIRST_ARG_OP
64162306a36Sopenharmony_ci *              index               - Which Local or Arg whose type to get
64262306a36Sopenharmony_ci *              walk_state          - Current walk state object
64362306a36Sopenharmony_ci *
64462306a36Sopenharmony_ci * RETURN:      Data type of current value of the selected Arg or Local
64562306a36Sopenharmony_ci *
64662306a36Sopenharmony_ci * DESCRIPTION: Get the type of the object stored in the Local or Arg
64762306a36Sopenharmony_ci *
64862306a36Sopenharmony_ci ******************************************************************************/
64962306a36Sopenharmony_ci
65062306a36Sopenharmony_ciacpi_object_type
65162306a36Sopenharmony_ciacpi_ds_method_data_get_type(u16 opcode,
65262306a36Sopenharmony_ci			     u32 index, struct acpi_walk_state *walk_state)
65362306a36Sopenharmony_ci{
65462306a36Sopenharmony_ci	acpi_status status;
65562306a36Sopenharmony_ci	struct acpi_namespace_node *node;
65662306a36Sopenharmony_ci	union acpi_operand_object *object;
65762306a36Sopenharmony_ci
65862306a36Sopenharmony_ci	ACPI_FUNCTION_TRACE(ds_method_data_get_type);
65962306a36Sopenharmony_ci
66062306a36Sopenharmony_ci	/* Get the namespace node for the arg/local */
66162306a36Sopenharmony_ci
66262306a36Sopenharmony_ci	status = acpi_ds_method_data_get_node(opcode, index, walk_state, &node);
66362306a36Sopenharmony_ci	if (ACPI_FAILURE(status)) {
66462306a36Sopenharmony_ci		return_VALUE((ACPI_TYPE_NOT_FOUND));
66562306a36Sopenharmony_ci	}
66662306a36Sopenharmony_ci
66762306a36Sopenharmony_ci	/* Get the object */
66862306a36Sopenharmony_ci
66962306a36Sopenharmony_ci	object = acpi_ns_get_attached_object(node);
67062306a36Sopenharmony_ci	if (!object) {
67162306a36Sopenharmony_ci
67262306a36Sopenharmony_ci		/* Uninitialized local/arg, return TYPE_ANY */
67362306a36Sopenharmony_ci
67462306a36Sopenharmony_ci		return_VALUE(ACPI_TYPE_ANY);
67562306a36Sopenharmony_ci	}
67662306a36Sopenharmony_ci
67762306a36Sopenharmony_ci	/* Get the object type */
67862306a36Sopenharmony_ci
67962306a36Sopenharmony_ci	return_VALUE(object->type);
68062306a36Sopenharmony_ci}
68162306a36Sopenharmony_ci#endif
682