162306a36Sopenharmony_ci// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
262306a36Sopenharmony_ci/*******************************************************************************
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * Module Name: dsutils - Dispatcher utilities
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci ******************************************************************************/
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include <acpi/acpi.h>
962306a36Sopenharmony_ci#include "accommon.h"
1062306a36Sopenharmony_ci#include "acparser.h"
1162306a36Sopenharmony_ci#include "amlcode.h"
1262306a36Sopenharmony_ci#include "acdispat.h"
1362306a36Sopenharmony_ci#include "acinterp.h"
1462306a36Sopenharmony_ci#include "acnamesp.h"
1562306a36Sopenharmony_ci#include "acdebug.h"
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci#define _COMPONENT          ACPI_DISPATCHER
1862306a36Sopenharmony_ciACPI_MODULE_NAME("dsutils")
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci/*******************************************************************************
2162306a36Sopenharmony_ci *
2262306a36Sopenharmony_ci * FUNCTION:    acpi_ds_clear_implicit_return
2362306a36Sopenharmony_ci *
2462306a36Sopenharmony_ci * PARAMETERS:  walk_state          - Current State
2562306a36Sopenharmony_ci *
2662306a36Sopenharmony_ci * RETURN:      None.
2762306a36Sopenharmony_ci *
2862306a36Sopenharmony_ci * DESCRIPTION: Clear and remove a reference on an implicit return value. Used
2962306a36Sopenharmony_ci *              to delete "stale" return values (if enabled, the return value
3062306a36Sopenharmony_ci *              from every operator is saved at least momentarily, in case the
3162306a36Sopenharmony_ci *              parent method exits.)
3262306a36Sopenharmony_ci *
3362306a36Sopenharmony_ci ******************************************************************************/
3462306a36Sopenharmony_civoid acpi_ds_clear_implicit_return(struct acpi_walk_state *walk_state)
3562306a36Sopenharmony_ci{
3662306a36Sopenharmony_ci	ACPI_FUNCTION_NAME(ds_clear_implicit_return);
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci	/*
3962306a36Sopenharmony_ci	 * Slack must be enabled for this feature
4062306a36Sopenharmony_ci	 */
4162306a36Sopenharmony_ci	if (!acpi_gbl_enable_interpreter_slack) {
4262306a36Sopenharmony_ci		return;
4362306a36Sopenharmony_ci	}
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci	if (walk_state->implicit_return_obj) {
4662306a36Sopenharmony_ci		/*
4762306a36Sopenharmony_ci		 * Delete any "stale" implicit return. However, in
4862306a36Sopenharmony_ci		 * complex statements, the implicit return value can be
4962306a36Sopenharmony_ci		 * bubbled up several levels.
5062306a36Sopenharmony_ci		 */
5162306a36Sopenharmony_ci		ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
5262306a36Sopenharmony_ci				  "Removing reference on stale implicit return obj %p\n",
5362306a36Sopenharmony_ci				  walk_state->implicit_return_obj));
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci		acpi_ut_remove_reference(walk_state->implicit_return_obj);
5662306a36Sopenharmony_ci		walk_state->implicit_return_obj = NULL;
5762306a36Sopenharmony_ci	}
5862306a36Sopenharmony_ci}
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci/*******************************************************************************
6162306a36Sopenharmony_ci *
6262306a36Sopenharmony_ci * FUNCTION:    acpi_ds_do_implicit_return
6362306a36Sopenharmony_ci *
6462306a36Sopenharmony_ci * PARAMETERS:  return_desc         - The return value
6562306a36Sopenharmony_ci *              walk_state          - Current State
6662306a36Sopenharmony_ci *              add_reference       - True if a reference should be added to the
6762306a36Sopenharmony_ci *                                    return object
6862306a36Sopenharmony_ci *
6962306a36Sopenharmony_ci * RETURN:      TRUE if implicit return enabled, FALSE otherwise
7062306a36Sopenharmony_ci *
7162306a36Sopenharmony_ci * DESCRIPTION: Implements the optional "implicit return".  We save the result
7262306a36Sopenharmony_ci *              of every ASL operator and control method invocation in case the
7362306a36Sopenharmony_ci *              parent method exit. Before storing a new return value, we
7462306a36Sopenharmony_ci *              delete the previous return value.
7562306a36Sopenharmony_ci *
7662306a36Sopenharmony_ci ******************************************************************************/
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ciu8
7962306a36Sopenharmony_ciacpi_ds_do_implicit_return(union acpi_operand_object *return_desc,
8062306a36Sopenharmony_ci			   struct acpi_walk_state *walk_state, u8 add_reference)
8162306a36Sopenharmony_ci{
8262306a36Sopenharmony_ci	ACPI_FUNCTION_NAME(ds_do_implicit_return);
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci	/*
8562306a36Sopenharmony_ci	 * Slack must be enabled for this feature, and we must
8662306a36Sopenharmony_ci	 * have a valid return object
8762306a36Sopenharmony_ci	 */
8862306a36Sopenharmony_ci	if ((!acpi_gbl_enable_interpreter_slack) || (!return_desc)) {
8962306a36Sopenharmony_ci		return (FALSE);
9062306a36Sopenharmony_ci	}
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci	ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
9362306a36Sopenharmony_ci			  "Result %p will be implicitly returned; Prev=%p\n",
9462306a36Sopenharmony_ci			  return_desc, walk_state->implicit_return_obj));
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci	/*
9762306a36Sopenharmony_ci	 * Delete any "stale" implicit return value first. However, in
9862306a36Sopenharmony_ci	 * complex statements, the implicit return value can be
9962306a36Sopenharmony_ci	 * bubbled up several levels, so we don't clear the value if it
10062306a36Sopenharmony_ci	 * is the same as the return_desc.
10162306a36Sopenharmony_ci	 */
10262306a36Sopenharmony_ci	if (walk_state->implicit_return_obj) {
10362306a36Sopenharmony_ci		if (walk_state->implicit_return_obj == return_desc) {
10462306a36Sopenharmony_ci			return (TRUE);
10562306a36Sopenharmony_ci		}
10662306a36Sopenharmony_ci		acpi_ds_clear_implicit_return(walk_state);
10762306a36Sopenharmony_ci	}
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci	/* Save the implicit return value, add a reference if requested */
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci	walk_state->implicit_return_obj = return_desc;
11262306a36Sopenharmony_ci	if (add_reference) {
11362306a36Sopenharmony_ci		acpi_ut_add_reference(return_desc);
11462306a36Sopenharmony_ci	}
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci	return (TRUE);
11762306a36Sopenharmony_ci}
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci/*******************************************************************************
12062306a36Sopenharmony_ci *
12162306a36Sopenharmony_ci * FUNCTION:    acpi_ds_is_result_used
12262306a36Sopenharmony_ci *
12362306a36Sopenharmony_ci * PARAMETERS:  op                  - Current Op
12462306a36Sopenharmony_ci *              walk_state          - Current State
12562306a36Sopenharmony_ci *
12662306a36Sopenharmony_ci * RETURN:      TRUE if result is used, FALSE otherwise
12762306a36Sopenharmony_ci *
12862306a36Sopenharmony_ci * DESCRIPTION: Check if a result object will be used by the parent
12962306a36Sopenharmony_ci *
13062306a36Sopenharmony_ci ******************************************************************************/
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ciu8
13362306a36Sopenharmony_ciacpi_ds_is_result_used(union acpi_parse_object * op,
13462306a36Sopenharmony_ci		       struct acpi_walk_state * walk_state)
13562306a36Sopenharmony_ci{
13662306a36Sopenharmony_ci	const struct acpi_opcode_info *parent_info;
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci	ACPI_FUNCTION_TRACE_PTR(ds_is_result_used, op);
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ci	/* Must have both an Op and a Result Object */
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci	if (!op) {
14362306a36Sopenharmony_ci		ACPI_ERROR((AE_INFO, "Null Op"));
14462306a36Sopenharmony_ci		return_UINT8(TRUE);
14562306a36Sopenharmony_ci	}
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci	/*
14862306a36Sopenharmony_ci	 * We know that this operator is not a
14962306a36Sopenharmony_ci	 * Return() operator (would not come here.) The following code is the
15062306a36Sopenharmony_ci	 * optional support for a so-called "implicit return". Some AML code
15162306a36Sopenharmony_ci	 * assumes that the last value of the method is "implicitly" returned
15262306a36Sopenharmony_ci	 * to the caller. Just save the last result as the return value.
15362306a36Sopenharmony_ci	 * NOTE: this is optional because the ASL language does not actually
15462306a36Sopenharmony_ci	 * support this behavior.
15562306a36Sopenharmony_ci	 */
15662306a36Sopenharmony_ci	(void)acpi_ds_do_implicit_return(walk_state->result_obj, walk_state,
15762306a36Sopenharmony_ci					 TRUE);
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci	/*
16062306a36Sopenharmony_ci	 * Now determine if the parent will use the result
16162306a36Sopenharmony_ci	 *
16262306a36Sopenharmony_ci	 * If there is no parent, or the parent is a scope_op, we are executing
16362306a36Sopenharmony_ci	 * at the method level. An executing method typically has no parent,
16462306a36Sopenharmony_ci	 * since each method is parsed separately. A method invoked externally
16562306a36Sopenharmony_ci	 * via execute_control_method has a scope_op as the parent.
16662306a36Sopenharmony_ci	 */
16762306a36Sopenharmony_ci	if ((!op->common.parent) ||
16862306a36Sopenharmony_ci	    (op->common.parent->common.aml_opcode == AML_SCOPE_OP)) {
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci		/* No parent, the return value cannot possibly be used */
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci		ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
17362306a36Sopenharmony_ci				  "At Method level, result of [%s] not used\n",
17462306a36Sopenharmony_ci				  acpi_ps_get_opcode_name(op->common.
17562306a36Sopenharmony_ci							  aml_opcode)));
17662306a36Sopenharmony_ci		return_UINT8(FALSE);
17762306a36Sopenharmony_ci	}
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci	/* Get info on the parent. The root_op is AML_SCOPE */
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci	parent_info =
18262306a36Sopenharmony_ci	    acpi_ps_get_opcode_info(op->common.parent->common.aml_opcode);
18362306a36Sopenharmony_ci	if (parent_info->class == AML_CLASS_UNKNOWN) {
18462306a36Sopenharmony_ci		ACPI_ERROR((AE_INFO, "Unknown parent opcode Op=%p", op));
18562306a36Sopenharmony_ci		return_UINT8(FALSE);
18662306a36Sopenharmony_ci	}
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci	/*
18962306a36Sopenharmony_ci	 * Decide what to do with the result based on the parent. If
19062306a36Sopenharmony_ci	 * the parent opcode will not use the result, delete the object.
19162306a36Sopenharmony_ci	 * Otherwise leave it as is, it will be deleted when it is used
19262306a36Sopenharmony_ci	 * as an operand later.
19362306a36Sopenharmony_ci	 */
19462306a36Sopenharmony_ci	switch (parent_info->class) {
19562306a36Sopenharmony_ci	case AML_CLASS_CONTROL:
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci		switch (op->common.parent->common.aml_opcode) {
19862306a36Sopenharmony_ci		case AML_RETURN_OP:
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_ci			/* Never delete the return value associated with a return opcode */
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci			goto result_used;
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci		case AML_IF_OP:
20562306a36Sopenharmony_ci		case AML_WHILE_OP:
20662306a36Sopenharmony_ci			/*
20762306a36Sopenharmony_ci			 * If we are executing the predicate AND this is the predicate op,
20862306a36Sopenharmony_ci			 * we will use the return value
20962306a36Sopenharmony_ci			 */
21062306a36Sopenharmony_ci			if ((walk_state->control_state->common.state ==
21162306a36Sopenharmony_ci			     ACPI_CONTROL_PREDICATE_EXECUTING) &&
21262306a36Sopenharmony_ci			    (walk_state->control_state->control.predicate_op ==
21362306a36Sopenharmony_ci			     op)) {
21462306a36Sopenharmony_ci				goto result_used;
21562306a36Sopenharmony_ci			}
21662306a36Sopenharmony_ci			break;
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_ci		default:
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci			/* Ignore other control opcodes */
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ci			break;
22362306a36Sopenharmony_ci		}
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci		/* The general control opcode returns no result */
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_ci		goto result_not_used;
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ci	case AML_CLASS_CREATE:
23062306a36Sopenharmony_ci		/*
23162306a36Sopenharmony_ci		 * These opcodes allow term_arg(s) as operands and therefore
23262306a36Sopenharmony_ci		 * the operands can be method calls. The result is used.
23362306a36Sopenharmony_ci		 */
23462306a36Sopenharmony_ci		goto result_used;
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ci	case AML_CLASS_NAMED_OBJECT:
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ci		if ((op->common.parent->common.aml_opcode == AML_REGION_OP) ||
23962306a36Sopenharmony_ci		    (op->common.parent->common.aml_opcode == AML_DATA_REGION_OP)
24062306a36Sopenharmony_ci		    || (op->common.parent->common.aml_opcode == AML_PACKAGE_OP)
24162306a36Sopenharmony_ci		    || (op->common.parent->common.aml_opcode == AML_BUFFER_OP)
24262306a36Sopenharmony_ci		    || (op->common.parent->common.aml_opcode ==
24362306a36Sopenharmony_ci			AML_VARIABLE_PACKAGE_OP)
24462306a36Sopenharmony_ci		    || (op->common.parent->common.aml_opcode ==
24562306a36Sopenharmony_ci			AML_INT_EVAL_SUBTREE_OP)
24662306a36Sopenharmony_ci		    || (op->common.parent->common.aml_opcode ==
24762306a36Sopenharmony_ci			AML_BANK_FIELD_OP)) {
24862306a36Sopenharmony_ci			/*
24962306a36Sopenharmony_ci			 * These opcodes allow term_arg(s) as operands and therefore
25062306a36Sopenharmony_ci			 * the operands can be method calls. The result is used.
25162306a36Sopenharmony_ci			 */
25262306a36Sopenharmony_ci			goto result_used;
25362306a36Sopenharmony_ci		}
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci		goto result_not_used;
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_ci	default:
25862306a36Sopenharmony_ci		/*
25962306a36Sopenharmony_ci		 * In all other cases. the parent will actually use the return
26062306a36Sopenharmony_ci		 * object, so keep it.
26162306a36Sopenharmony_ci		 */
26262306a36Sopenharmony_ci		goto result_used;
26362306a36Sopenharmony_ci	}
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ciresult_used:
26662306a36Sopenharmony_ci	ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
26762306a36Sopenharmony_ci			  "Result of [%s] used by Parent [%s] Op=%p\n",
26862306a36Sopenharmony_ci			  acpi_ps_get_opcode_name(op->common.aml_opcode),
26962306a36Sopenharmony_ci			  acpi_ps_get_opcode_name(op->common.parent->common.
27062306a36Sopenharmony_ci						  aml_opcode), op));
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ci	return_UINT8(TRUE);
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_ciresult_not_used:
27562306a36Sopenharmony_ci	ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
27662306a36Sopenharmony_ci			  "Result of [%s] not used by Parent [%s] Op=%p\n",
27762306a36Sopenharmony_ci			  acpi_ps_get_opcode_name(op->common.aml_opcode),
27862306a36Sopenharmony_ci			  acpi_ps_get_opcode_name(op->common.parent->common.
27962306a36Sopenharmony_ci						  aml_opcode), op));
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_ci	return_UINT8(FALSE);
28262306a36Sopenharmony_ci}
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_ci/*******************************************************************************
28562306a36Sopenharmony_ci *
28662306a36Sopenharmony_ci * FUNCTION:    acpi_ds_delete_result_if_not_used
28762306a36Sopenharmony_ci *
28862306a36Sopenharmony_ci * PARAMETERS:  op              - Current parse Op
28962306a36Sopenharmony_ci *              result_obj      - Result of the operation
29062306a36Sopenharmony_ci *              walk_state      - Current state
29162306a36Sopenharmony_ci *
29262306a36Sopenharmony_ci * RETURN:      Status
29362306a36Sopenharmony_ci *
29462306a36Sopenharmony_ci * DESCRIPTION: Used after interpretation of an opcode. If there is an internal
29562306a36Sopenharmony_ci *              result descriptor, check if the parent opcode will actually use
29662306a36Sopenharmony_ci *              this result. If not, delete the result now so that it will
29762306a36Sopenharmony_ci *              not become orphaned.
29862306a36Sopenharmony_ci *
29962306a36Sopenharmony_ci ******************************************************************************/
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_civoid
30262306a36Sopenharmony_ciacpi_ds_delete_result_if_not_used(union acpi_parse_object *op,
30362306a36Sopenharmony_ci				  union acpi_operand_object *result_obj,
30462306a36Sopenharmony_ci				  struct acpi_walk_state *walk_state)
30562306a36Sopenharmony_ci{
30662306a36Sopenharmony_ci	union acpi_operand_object *obj_desc;
30762306a36Sopenharmony_ci	acpi_status status;
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ci	ACPI_FUNCTION_TRACE_PTR(ds_delete_result_if_not_used, result_obj);
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ci	if (!op) {
31262306a36Sopenharmony_ci		ACPI_ERROR((AE_INFO, "Null Op"));
31362306a36Sopenharmony_ci		return_VOID;
31462306a36Sopenharmony_ci	}
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_ci	if (!result_obj) {
31762306a36Sopenharmony_ci		return_VOID;
31862306a36Sopenharmony_ci	}
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_ci	if (!acpi_ds_is_result_used(op, walk_state)) {
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_ci		/* Must pop the result stack (obj_desc should be equal to result_obj) */
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_ci		status = acpi_ds_result_pop(&obj_desc, walk_state);
32562306a36Sopenharmony_ci		if (ACPI_SUCCESS(status)) {
32662306a36Sopenharmony_ci			acpi_ut_remove_reference(result_obj);
32762306a36Sopenharmony_ci		}
32862306a36Sopenharmony_ci	}
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ci	return_VOID;
33162306a36Sopenharmony_ci}
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_ci/*******************************************************************************
33462306a36Sopenharmony_ci *
33562306a36Sopenharmony_ci * FUNCTION:    acpi_ds_resolve_operands
33662306a36Sopenharmony_ci *
33762306a36Sopenharmony_ci * PARAMETERS:  walk_state          - Current walk state with operands on stack
33862306a36Sopenharmony_ci *
33962306a36Sopenharmony_ci * RETURN:      Status
34062306a36Sopenharmony_ci *
34162306a36Sopenharmony_ci * DESCRIPTION: Resolve all operands to their values. Used to prepare
34262306a36Sopenharmony_ci *              arguments to a control method invocation (a call from one
34362306a36Sopenharmony_ci *              method to another.)
34462306a36Sopenharmony_ci *
34562306a36Sopenharmony_ci ******************************************************************************/
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_ciacpi_status acpi_ds_resolve_operands(struct acpi_walk_state *walk_state)
34862306a36Sopenharmony_ci{
34962306a36Sopenharmony_ci	u32 i;
35062306a36Sopenharmony_ci	acpi_status status = AE_OK;
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_ci	ACPI_FUNCTION_TRACE_PTR(ds_resolve_operands, walk_state);
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_ci	/*
35562306a36Sopenharmony_ci	 * Attempt to resolve each of the valid operands
35662306a36Sopenharmony_ci	 * Method arguments are passed by reference, not by value. This means
35762306a36Sopenharmony_ci	 * that the actual objects are passed, not copies of the objects.
35862306a36Sopenharmony_ci	 */
35962306a36Sopenharmony_ci	for (i = 0; i < walk_state->num_operands; i++) {
36062306a36Sopenharmony_ci		status =
36162306a36Sopenharmony_ci		    acpi_ex_resolve_to_value(&walk_state->operands[i],
36262306a36Sopenharmony_ci					     walk_state);
36362306a36Sopenharmony_ci		if (ACPI_FAILURE(status)) {
36462306a36Sopenharmony_ci			break;
36562306a36Sopenharmony_ci		}
36662306a36Sopenharmony_ci	}
36762306a36Sopenharmony_ci
36862306a36Sopenharmony_ci	return_ACPI_STATUS(status);
36962306a36Sopenharmony_ci}
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_ci/*******************************************************************************
37262306a36Sopenharmony_ci *
37362306a36Sopenharmony_ci * FUNCTION:    acpi_ds_clear_operands
37462306a36Sopenharmony_ci *
37562306a36Sopenharmony_ci * PARAMETERS:  walk_state          - Current walk state with operands on stack
37662306a36Sopenharmony_ci *
37762306a36Sopenharmony_ci * RETURN:      None
37862306a36Sopenharmony_ci *
37962306a36Sopenharmony_ci * DESCRIPTION: Clear all operands on the current walk state operand stack.
38062306a36Sopenharmony_ci *
38162306a36Sopenharmony_ci ******************************************************************************/
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_civoid acpi_ds_clear_operands(struct acpi_walk_state *walk_state)
38462306a36Sopenharmony_ci{
38562306a36Sopenharmony_ci	u32 i;
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ci	ACPI_FUNCTION_TRACE_PTR(ds_clear_operands, walk_state);
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_ci	/* Remove a reference on each operand on the stack */
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_ci	for (i = 0; i < walk_state->num_operands; i++) {
39262306a36Sopenharmony_ci		/*
39362306a36Sopenharmony_ci		 * Remove a reference to all operands, including both
39462306a36Sopenharmony_ci		 * "Arguments" and "Targets".
39562306a36Sopenharmony_ci		 */
39662306a36Sopenharmony_ci		acpi_ut_remove_reference(walk_state->operands[i]);
39762306a36Sopenharmony_ci		walk_state->operands[i] = NULL;
39862306a36Sopenharmony_ci	}
39962306a36Sopenharmony_ci
40062306a36Sopenharmony_ci	walk_state->num_operands = 0;
40162306a36Sopenharmony_ci	return_VOID;
40262306a36Sopenharmony_ci}
40362306a36Sopenharmony_ci
40462306a36Sopenharmony_ci/*******************************************************************************
40562306a36Sopenharmony_ci *
40662306a36Sopenharmony_ci * FUNCTION:    acpi_ds_create_operand
40762306a36Sopenharmony_ci *
40862306a36Sopenharmony_ci * PARAMETERS:  walk_state      - Current walk state
40962306a36Sopenharmony_ci *              arg             - Parse object for the argument
41062306a36Sopenharmony_ci *              arg_index       - Which argument (zero based)
41162306a36Sopenharmony_ci *
41262306a36Sopenharmony_ci * RETURN:      Status
41362306a36Sopenharmony_ci *
41462306a36Sopenharmony_ci * DESCRIPTION: Translate a parse tree object that is an argument to an AML
41562306a36Sopenharmony_ci *              opcode to the equivalent interpreter object. This may include
41662306a36Sopenharmony_ci *              looking up a name or entering a new name into the internal
41762306a36Sopenharmony_ci *              namespace.
41862306a36Sopenharmony_ci *
41962306a36Sopenharmony_ci ******************************************************************************/
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_ciacpi_status
42262306a36Sopenharmony_ciacpi_ds_create_operand(struct acpi_walk_state *walk_state,
42362306a36Sopenharmony_ci		       union acpi_parse_object *arg, u32 arg_index)
42462306a36Sopenharmony_ci{
42562306a36Sopenharmony_ci	acpi_status status = AE_OK;
42662306a36Sopenharmony_ci	char *name_string;
42762306a36Sopenharmony_ci	u32 name_length;
42862306a36Sopenharmony_ci	union acpi_operand_object *obj_desc;
42962306a36Sopenharmony_ci	union acpi_parse_object *parent_op;
43062306a36Sopenharmony_ci	u16 opcode;
43162306a36Sopenharmony_ci	acpi_interpreter_mode interpreter_mode;
43262306a36Sopenharmony_ci	const struct acpi_opcode_info *op_info;
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_ci	ACPI_FUNCTION_TRACE_PTR(ds_create_operand, arg);
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_ci	/* A valid name must be looked up in the namespace */
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_ci	if ((arg->common.aml_opcode == AML_INT_NAMEPATH_OP) &&
43962306a36Sopenharmony_ci	    (arg->common.value.string) &&
44062306a36Sopenharmony_ci	    !(arg->common.flags & ACPI_PARSEOP_IN_STACK)) {
44162306a36Sopenharmony_ci		ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, "Getting a name: Arg=%p\n",
44262306a36Sopenharmony_ci				  arg));
44362306a36Sopenharmony_ci
44462306a36Sopenharmony_ci		/* Get the entire name string from the AML stream */
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_ci		status = acpi_ex_get_name_string(ACPI_TYPE_ANY,
44762306a36Sopenharmony_ci						 arg->common.value.buffer,
44862306a36Sopenharmony_ci						 &name_string, &name_length);
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_ci		if (ACPI_FAILURE(status)) {
45162306a36Sopenharmony_ci			return_ACPI_STATUS(status);
45262306a36Sopenharmony_ci		}
45362306a36Sopenharmony_ci
45462306a36Sopenharmony_ci		/* All prefixes have been handled, and the name is in name_string */
45562306a36Sopenharmony_ci
45662306a36Sopenharmony_ci		/*
45762306a36Sopenharmony_ci		 * Special handling for buffer_field declarations. This is a deferred
45862306a36Sopenharmony_ci		 * opcode that unfortunately defines the field name as the last
45962306a36Sopenharmony_ci		 * parameter instead of the first. We get here when we are performing
46062306a36Sopenharmony_ci		 * the deferred execution, so the actual name of the field is already
46162306a36Sopenharmony_ci		 * in the namespace. We don't want to attempt to look it up again
46262306a36Sopenharmony_ci		 * because we may be executing in a different scope than where the
46362306a36Sopenharmony_ci		 * actual opcode exists.
46462306a36Sopenharmony_ci		 */
46562306a36Sopenharmony_ci		if ((walk_state->deferred_node) &&
46662306a36Sopenharmony_ci		    (walk_state->deferred_node->type == ACPI_TYPE_BUFFER_FIELD)
46762306a36Sopenharmony_ci		    && (arg_index == (u32)
46862306a36Sopenharmony_ci			((walk_state->opcode == AML_CREATE_FIELD_OP) ? 3 : 2))) {
46962306a36Sopenharmony_ci			obj_desc =
47062306a36Sopenharmony_ci			    ACPI_CAST_PTR(union acpi_operand_object,
47162306a36Sopenharmony_ci					  walk_state->deferred_node);
47262306a36Sopenharmony_ci			status = AE_OK;
47362306a36Sopenharmony_ci		} else {	/* All other opcodes */
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_ci			/*
47662306a36Sopenharmony_ci			 * Differentiate between a namespace "create" operation
47762306a36Sopenharmony_ci			 * versus a "lookup" operation (IMODE_LOAD_PASS2 vs.
47862306a36Sopenharmony_ci			 * IMODE_EXECUTE) in order to support the creation of
47962306a36Sopenharmony_ci			 * namespace objects during the execution of control methods.
48062306a36Sopenharmony_ci			 */
48162306a36Sopenharmony_ci			parent_op = arg->common.parent;
48262306a36Sopenharmony_ci			op_info =
48362306a36Sopenharmony_ci			    acpi_ps_get_opcode_info(parent_op->common.
48462306a36Sopenharmony_ci						    aml_opcode);
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_ci			if ((op_info->flags & AML_NSNODE) &&
48762306a36Sopenharmony_ci			    (parent_op->common.aml_opcode !=
48862306a36Sopenharmony_ci			     AML_INT_METHODCALL_OP)
48962306a36Sopenharmony_ci			    && (parent_op->common.aml_opcode != AML_REGION_OP)
49062306a36Sopenharmony_ci			    && (parent_op->common.aml_opcode !=
49162306a36Sopenharmony_ci				AML_INT_NAMEPATH_OP)) {
49262306a36Sopenharmony_ci
49362306a36Sopenharmony_ci				/* Enter name into namespace if not found */
49462306a36Sopenharmony_ci
49562306a36Sopenharmony_ci				interpreter_mode = ACPI_IMODE_LOAD_PASS2;
49662306a36Sopenharmony_ci			} else {
49762306a36Sopenharmony_ci				/* Return a failure if name not found */
49862306a36Sopenharmony_ci
49962306a36Sopenharmony_ci				interpreter_mode = ACPI_IMODE_EXECUTE;
50062306a36Sopenharmony_ci			}
50162306a36Sopenharmony_ci
50262306a36Sopenharmony_ci			status =
50362306a36Sopenharmony_ci			    acpi_ns_lookup(walk_state->scope_info, name_string,
50462306a36Sopenharmony_ci					   ACPI_TYPE_ANY, interpreter_mode,
50562306a36Sopenharmony_ci					   ACPI_NS_SEARCH_PARENT |
50662306a36Sopenharmony_ci					   ACPI_NS_DONT_OPEN_SCOPE, walk_state,
50762306a36Sopenharmony_ci					   ACPI_CAST_INDIRECT_PTR(struct
50862306a36Sopenharmony_ci								  acpi_namespace_node,
50962306a36Sopenharmony_ci								  &obj_desc));
51062306a36Sopenharmony_ci			/*
51162306a36Sopenharmony_ci			 * The only case where we pass through (ignore) a NOT_FOUND
51262306a36Sopenharmony_ci			 * error is for the cond_ref_of opcode.
51362306a36Sopenharmony_ci			 */
51462306a36Sopenharmony_ci			if (status == AE_NOT_FOUND) {
51562306a36Sopenharmony_ci				if (parent_op->common.aml_opcode ==
51662306a36Sopenharmony_ci				    AML_CONDITIONAL_REF_OF_OP) {
51762306a36Sopenharmony_ci					/*
51862306a36Sopenharmony_ci					 * For the Conditional Reference op, it's OK if
51962306a36Sopenharmony_ci					 * the name is not found;  We just need a way to
52062306a36Sopenharmony_ci					 * indicate this to the interpreter, set the
52162306a36Sopenharmony_ci					 * object to the root
52262306a36Sopenharmony_ci					 */
52362306a36Sopenharmony_ci					obj_desc =
52462306a36Sopenharmony_ci					    ACPI_CAST_PTR(union
52562306a36Sopenharmony_ci								 acpi_operand_object,
52662306a36Sopenharmony_ci								 acpi_gbl_root_node);
52762306a36Sopenharmony_ci					status = AE_OK;
52862306a36Sopenharmony_ci				} else if (parent_op->common.aml_opcode ==
52962306a36Sopenharmony_ci					   AML_EXTERNAL_OP) {
53062306a36Sopenharmony_ci					/*
53162306a36Sopenharmony_ci					 * This opcode should never appear here. It is used only
53262306a36Sopenharmony_ci					 * by AML disassemblers and is surrounded by an If(0)
53362306a36Sopenharmony_ci					 * by the ASL compiler.
53462306a36Sopenharmony_ci					 *
53562306a36Sopenharmony_ci					 * Therefore, if we see it here, it is a serious error.
53662306a36Sopenharmony_ci					 */
53762306a36Sopenharmony_ci					status = AE_AML_BAD_OPCODE;
53862306a36Sopenharmony_ci				} else {
53962306a36Sopenharmony_ci					/*
54062306a36Sopenharmony_ci					 * We just plain didn't find it -- which is a
54162306a36Sopenharmony_ci					 * very serious error at this point
54262306a36Sopenharmony_ci					 */
54362306a36Sopenharmony_ci					status = AE_AML_NAME_NOT_FOUND;
54462306a36Sopenharmony_ci				}
54562306a36Sopenharmony_ci			}
54662306a36Sopenharmony_ci
54762306a36Sopenharmony_ci			if (ACPI_FAILURE(status)) {
54862306a36Sopenharmony_ci				ACPI_ERROR_NAMESPACE(walk_state->scope_info,
54962306a36Sopenharmony_ci						     name_string, status);
55062306a36Sopenharmony_ci			}
55162306a36Sopenharmony_ci		}
55262306a36Sopenharmony_ci
55362306a36Sopenharmony_ci		/* Free the namestring created above */
55462306a36Sopenharmony_ci
55562306a36Sopenharmony_ci		ACPI_FREE(name_string);
55662306a36Sopenharmony_ci
55762306a36Sopenharmony_ci		/* Check status from the lookup */
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_ci		if (ACPI_FAILURE(status)) {
56062306a36Sopenharmony_ci			return_ACPI_STATUS(status);
56162306a36Sopenharmony_ci		}
56262306a36Sopenharmony_ci
56362306a36Sopenharmony_ci		/* Put the resulting object onto the current object stack */
56462306a36Sopenharmony_ci
56562306a36Sopenharmony_ci		status = acpi_ds_obj_stack_push(obj_desc, walk_state);
56662306a36Sopenharmony_ci		if (ACPI_FAILURE(status)) {
56762306a36Sopenharmony_ci			return_ACPI_STATUS(status);
56862306a36Sopenharmony_ci		}
56962306a36Sopenharmony_ci
57062306a36Sopenharmony_ci		acpi_db_display_argument_object(obj_desc, walk_state);
57162306a36Sopenharmony_ci	} else {
57262306a36Sopenharmony_ci		/* Check for null name case */
57362306a36Sopenharmony_ci
57462306a36Sopenharmony_ci		if ((arg->common.aml_opcode == AML_INT_NAMEPATH_OP) &&
57562306a36Sopenharmony_ci		    !(arg->common.flags & ACPI_PARSEOP_IN_STACK)) {
57662306a36Sopenharmony_ci			/*
57762306a36Sopenharmony_ci			 * If the name is null, this means that this is an
57862306a36Sopenharmony_ci			 * optional result parameter that was not specified
57962306a36Sopenharmony_ci			 * in the original ASL. Create a Zero Constant for a
58062306a36Sopenharmony_ci			 * placeholder. (Store to a constant is a Noop.)
58162306a36Sopenharmony_ci			 */
58262306a36Sopenharmony_ci			opcode = AML_ZERO_OP;	/* Has no arguments! */
58362306a36Sopenharmony_ci
58462306a36Sopenharmony_ci			ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
58562306a36Sopenharmony_ci					  "Null namepath: Arg=%p\n", arg));
58662306a36Sopenharmony_ci		} else {
58762306a36Sopenharmony_ci			opcode = arg->common.aml_opcode;
58862306a36Sopenharmony_ci		}
58962306a36Sopenharmony_ci
59062306a36Sopenharmony_ci		/* Get the object type of the argument */
59162306a36Sopenharmony_ci
59262306a36Sopenharmony_ci		op_info = acpi_ps_get_opcode_info(opcode);
59362306a36Sopenharmony_ci		if (op_info->object_type == ACPI_TYPE_INVALID) {
59462306a36Sopenharmony_ci			return_ACPI_STATUS(AE_NOT_IMPLEMENTED);
59562306a36Sopenharmony_ci		}
59662306a36Sopenharmony_ci
59762306a36Sopenharmony_ci		if ((op_info->flags & AML_HAS_RETVAL) ||
59862306a36Sopenharmony_ci		    (arg->common.flags & ACPI_PARSEOP_IN_STACK)) {
59962306a36Sopenharmony_ci			/*
60062306a36Sopenharmony_ci			 * Use value that was already previously returned
60162306a36Sopenharmony_ci			 * by the evaluation of this argument
60262306a36Sopenharmony_ci			 */
60362306a36Sopenharmony_ci			status = acpi_ds_result_pop(&obj_desc, walk_state);
60462306a36Sopenharmony_ci			if (ACPI_FAILURE(status)) {
60562306a36Sopenharmony_ci				/*
60662306a36Sopenharmony_ci				 * Only error is underflow, and this indicates
60762306a36Sopenharmony_ci				 * a missing or null operand!
60862306a36Sopenharmony_ci				 */
60962306a36Sopenharmony_ci				ACPI_EXCEPTION((AE_INFO, status,
61062306a36Sopenharmony_ci						"Missing or null operand"));
61162306a36Sopenharmony_ci				return_ACPI_STATUS(status);
61262306a36Sopenharmony_ci			}
61362306a36Sopenharmony_ci		} else {
61462306a36Sopenharmony_ci			/* Create an ACPI_INTERNAL_OBJECT for the argument */
61562306a36Sopenharmony_ci
61662306a36Sopenharmony_ci			obj_desc =
61762306a36Sopenharmony_ci			    acpi_ut_create_internal_object(op_info->
61862306a36Sopenharmony_ci							   object_type);
61962306a36Sopenharmony_ci			if (!obj_desc) {
62062306a36Sopenharmony_ci				return_ACPI_STATUS(AE_NO_MEMORY);
62162306a36Sopenharmony_ci			}
62262306a36Sopenharmony_ci
62362306a36Sopenharmony_ci			/* Initialize the new object */
62462306a36Sopenharmony_ci
62562306a36Sopenharmony_ci			status =
62662306a36Sopenharmony_ci			    acpi_ds_init_object_from_op(walk_state, arg, opcode,
62762306a36Sopenharmony_ci							&obj_desc);
62862306a36Sopenharmony_ci			if (ACPI_FAILURE(status)) {
62962306a36Sopenharmony_ci				acpi_ut_delete_object_desc(obj_desc);
63062306a36Sopenharmony_ci				return_ACPI_STATUS(status);
63162306a36Sopenharmony_ci			}
63262306a36Sopenharmony_ci		}
63362306a36Sopenharmony_ci
63462306a36Sopenharmony_ci		/* Put the operand object on the object stack */
63562306a36Sopenharmony_ci
63662306a36Sopenharmony_ci		status = acpi_ds_obj_stack_push(obj_desc, walk_state);
63762306a36Sopenharmony_ci		if (ACPI_FAILURE(status)) {
63862306a36Sopenharmony_ci			return_ACPI_STATUS(status);
63962306a36Sopenharmony_ci		}
64062306a36Sopenharmony_ci
64162306a36Sopenharmony_ci		acpi_db_display_argument_object(obj_desc, walk_state);
64262306a36Sopenharmony_ci	}
64362306a36Sopenharmony_ci
64462306a36Sopenharmony_ci	return_ACPI_STATUS(AE_OK);
64562306a36Sopenharmony_ci}
64662306a36Sopenharmony_ci
64762306a36Sopenharmony_ci/*******************************************************************************
64862306a36Sopenharmony_ci *
64962306a36Sopenharmony_ci * FUNCTION:    acpi_ds_create_operands
65062306a36Sopenharmony_ci *
65162306a36Sopenharmony_ci * PARAMETERS:  walk_state          - Current state
65262306a36Sopenharmony_ci *              first_arg           - First argument of a parser argument tree
65362306a36Sopenharmony_ci *
65462306a36Sopenharmony_ci * RETURN:      Status
65562306a36Sopenharmony_ci *
65662306a36Sopenharmony_ci * DESCRIPTION: Convert an operator's arguments from a parse tree format to
65762306a36Sopenharmony_ci *              namespace objects and place those argument object on the object
65862306a36Sopenharmony_ci *              stack in preparation for evaluation by the interpreter.
65962306a36Sopenharmony_ci *
66062306a36Sopenharmony_ci ******************************************************************************/
66162306a36Sopenharmony_ci
66262306a36Sopenharmony_ciacpi_status
66362306a36Sopenharmony_ciacpi_ds_create_operands(struct acpi_walk_state *walk_state,
66462306a36Sopenharmony_ci			union acpi_parse_object *first_arg)
66562306a36Sopenharmony_ci{
66662306a36Sopenharmony_ci	acpi_status status = AE_OK;
66762306a36Sopenharmony_ci	union acpi_parse_object *arg;
66862306a36Sopenharmony_ci	union acpi_parse_object *arguments[ACPI_OBJ_NUM_OPERANDS];
66962306a36Sopenharmony_ci	u32 arg_count = 0;
67062306a36Sopenharmony_ci	u32 index = walk_state->num_operands;
67162306a36Sopenharmony_ci	u32 i;
67262306a36Sopenharmony_ci
67362306a36Sopenharmony_ci	ACPI_FUNCTION_TRACE_PTR(ds_create_operands, first_arg);
67462306a36Sopenharmony_ci
67562306a36Sopenharmony_ci	/* Get all arguments in the list */
67662306a36Sopenharmony_ci
67762306a36Sopenharmony_ci	arg = first_arg;
67862306a36Sopenharmony_ci	while (arg) {
67962306a36Sopenharmony_ci		if (index >= ACPI_OBJ_NUM_OPERANDS) {
68062306a36Sopenharmony_ci			return_ACPI_STATUS(AE_BAD_DATA);
68162306a36Sopenharmony_ci		}
68262306a36Sopenharmony_ci
68362306a36Sopenharmony_ci		arguments[index] = arg;
68462306a36Sopenharmony_ci		walk_state->operands[index] = NULL;
68562306a36Sopenharmony_ci
68662306a36Sopenharmony_ci		/* Move on to next argument, if any */
68762306a36Sopenharmony_ci
68862306a36Sopenharmony_ci		arg = arg->common.next;
68962306a36Sopenharmony_ci		arg_count++;
69062306a36Sopenharmony_ci		index++;
69162306a36Sopenharmony_ci	}
69262306a36Sopenharmony_ci
69362306a36Sopenharmony_ci	ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
69462306a36Sopenharmony_ci			  "NumOperands %d, ArgCount %d, Index %d\n",
69562306a36Sopenharmony_ci			  walk_state->num_operands, arg_count, index));
69662306a36Sopenharmony_ci
69762306a36Sopenharmony_ci	/* Create the interpreter arguments, in reverse order */
69862306a36Sopenharmony_ci
69962306a36Sopenharmony_ci	index--;
70062306a36Sopenharmony_ci	for (i = 0; i < arg_count; i++) {
70162306a36Sopenharmony_ci		arg = arguments[index];
70262306a36Sopenharmony_ci		walk_state->operand_index = (u8)index;
70362306a36Sopenharmony_ci
70462306a36Sopenharmony_ci		status = acpi_ds_create_operand(walk_state, arg, index);
70562306a36Sopenharmony_ci		if (ACPI_FAILURE(status)) {
70662306a36Sopenharmony_ci			goto cleanup;
70762306a36Sopenharmony_ci		}
70862306a36Sopenharmony_ci
70962306a36Sopenharmony_ci		ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
71062306a36Sopenharmony_ci				  "Created Arg #%u (%p) %u args total\n",
71162306a36Sopenharmony_ci				  index, arg, arg_count));
71262306a36Sopenharmony_ci		index--;
71362306a36Sopenharmony_ci	}
71462306a36Sopenharmony_ci
71562306a36Sopenharmony_ci	return_ACPI_STATUS(status);
71662306a36Sopenharmony_ci
71762306a36Sopenharmony_cicleanup:
71862306a36Sopenharmony_ci	/*
71962306a36Sopenharmony_ci	 * We must undo everything done above; meaning that we must
72062306a36Sopenharmony_ci	 * pop everything off of the operand stack and delete those
72162306a36Sopenharmony_ci	 * objects
72262306a36Sopenharmony_ci	 */
72362306a36Sopenharmony_ci	acpi_ds_obj_stack_pop_and_delete(arg_count, walk_state);
72462306a36Sopenharmony_ci
72562306a36Sopenharmony_ci	ACPI_EXCEPTION((AE_INFO, status, "While creating Arg %u", index));
72662306a36Sopenharmony_ci	return_ACPI_STATUS(status);
72762306a36Sopenharmony_ci}
72862306a36Sopenharmony_ci
72962306a36Sopenharmony_ci/*****************************************************************************
73062306a36Sopenharmony_ci *
73162306a36Sopenharmony_ci * FUNCTION:    acpi_ds_evaluate_name_path
73262306a36Sopenharmony_ci *
73362306a36Sopenharmony_ci * PARAMETERS:  walk_state      - Current state of the parse tree walk,
73462306a36Sopenharmony_ci *                                the opcode of current operation should be
73562306a36Sopenharmony_ci *                                AML_INT_NAMEPATH_OP
73662306a36Sopenharmony_ci *
73762306a36Sopenharmony_ci * RETURN:      Status
73862306a36Sopenharmony_ci *
73962306a36Sopenharmony_ci * DESCRIPTION: Translate the -name_path- parse tree object to the equivalent
74062306a36Sopenharmony_ci *              interpreter object, convert it to value, if needed, duplicate
74162306a36Sopenharmony_ci *              it, if needed, and push it onto the current result stack.
74262306a36Sopenharmony_ci *
74362306a36Sopenharmony_ci ****************************************************************************/
74462306a36Sopenharmony_ci
74562306a36Sopenharmony_ciacpi_status acpi_ds_evaluate_name_path(struct acpi_walk_state *walk_state)
74662306a36Sopenharmony_ci{
74762306a36Sopenharmony_ci	acpi_status status = AE_OK;
74862306a36Sopenharmony_ci	union acpi_parse_object *op = walk_state->op;
74962306a36Sopenharmony_ci	union acpi_operand_object **operand = &walk_state->operands[0];
75062306a36Sopenharmony_ci	union acpi_operand_object *new_obj_desc;
75162306a36Sopenharmony_ci	u8 type;
75262306a36Sopenharmony_ci
75362306a36Sopenharmony_ci	ACPI_FUNCTION_TRACE_PTR(ds_evaluate_name_path, walk_state);
75462306a36Sopenharmony_ci
75562306a36Sopenharmony_ci	if (!op->common.parent) {
75662306a36Sopenharmony_ci
75762306a36Sopenharmony_ci		/* This happens after certain exception processing */
75862306a36Sopenharmony_ci
75962306a36Sopenharmony_ci		goto exit;
76062306a36Sopenharmony_ci	}
76162306a36Sopenharmony_ci
76262306a36Sopenharmony_ci	if ((op->common.parent->common.aml_opcode == AML_PACKAGE_OP) ||
76362306a36Sopenharmony_ci	    (op->common.parent->common.aml_opcode == AML_VARIABLE_PACKAGE_OP) ||
76462306a36Sopenharmony_ci	    (op->common.parent->common.aml_opcode == AML_REF_OF_OP)) {
76562306a36Sopenharmony_ci
76662306a36Sopenharmony_ci		/* TBD: Should we specify this feature as a bit of op_info->Flags of these opcodes? */
76762306a36Sopenharmony_ci
76862306a36Sopenharmony_ci		goto exit;
76962306a36Sopenharmony_ci	}
77062306a36Sopenharmony_ci
77162306a36Sopenharmony_ci	status = acpi_ds_create_operand(walk_state, op, 0);
77262306a36Sopenharmony_ci	if (ACPI_FAILURE(status)) {
77362306a36Sopenharmony_ci		goto exit;
77462306a36Sopenharmony_ci	}
77562306a36Sopenharmony_ci
77662306a36Sopenharmony_ci	if (op->common.flags & ACPI_PARSEOP_TARGET) {
77762306a36Sopenharmony_ci		new_obj_desc = *operand;
77862306a36Sopenharmony_ci		goto push_result;
77962306a36Sopenharmony_ci	}
78062306a36Sopenharmony_ci
78162306a36Sopenharmony_ci	type = (*operand)->common.type;
78262306a36Sopenharmony_ci
78362306a36Sopenharmony_ci	status = acpi_ex_resolve_to_value(operand, walk_state);
78462306a36Sopenharmony_ci	if (ACPI_FAILURE(status)) {
78562306a36Sopenharmony_ci		goto exit;
78662306a36Sopenharmony_ci	}
78762306a36Sopenharmony_ci
78862306a36Sopenharmony_ci	if (type == ACPI_TYPE_INTEGER) {
78962306a36Sopenharmony_ci
79062306a36Sopenharmony_ci		/* It was incremented by acpi_ex_resolve_to_value */
79162306a36Sopenharmony_ci
79262306a36Sopenharmony_ci		acpi_ut_remove_reference(*operand);
79362306a36Sopenharmony_ci
79462306a36Sopenharmony_ci		status =
79562306a36Sopenharmony_ci		    acpi_ut_copy_iobject_to_iobject(*operand, &new_obj_desc,
79662306a36Sopenharmony_ci						    walk_state);
79762306a36Sopenharmony_ci		if (ACPI_FAILURE(status)) {
79862306a36Sopenharmony_ci			goto exit;
79962306a36Sopenharmony_ci		}
80062306a36Sopenharmony_ci	} else {
80162306a36Sopenharmony_ci		/*
80262306a36Sopenharmony_ci		 * The object either was anew created or is
80362306a36Sopenharmony_ci		 * a Namespace node - don't decrement it.
80462306a36Sopenharmony_ci		 */
80562306a36Sopenharmony_ci		new_obj_desc = *operand;
80662306a36Sopenharmony_ci	}
80762306a36Sopenharmony_ci
80862306a36Sopenharmony_ci	/* Cleanup for name-path operand */
80962306a36Sopenharmony_ci
81062306a36Sopenharmony_ci	status = acpi_ds_obj_stack_pop(1, walk_state);
81162306a36Sopenharmony_ci	if (ACPI_FAILURE(status)) {
81262306a36Sopenharmony_ci		walk_state->result_obj = new_obj_desc;
81362306a36Sopenharmony_ci		goto exit;
81462306a36Sopenharmony_ci	}
81562306a36Sopenharmony_ci
81662306a36Sopenharmony_cipush_result:
81762306a36Sopenharmony_ci
81862306a36Sopenharmony_ci	walk_state->result_obj = new_obj_desc;
81962306a36Sopenharmony_ci
82062306a36Sopenharmony_ci	status = acpi_ds_result_push(walk_state->result_obj, walk_state);
82162306a36Sopenharmony_ci	if (ACPI_SUCCESS(status)) {
82262306a36Sopenharmony_ci
82362306a36Sopenharmony_ci		/* Force to take it from stack */
82462306a36Sopenharmony_ci
82562306a36Sopenharmony_ci		op->common.flags |= ACPI_PARSEOP_IN_STACK;
82662306a36Sopenharmony_ci	}
82762306a36Sopenharmony_ci
82862306a36Sopenharmony_ciexit:
82962306a36Sopenharmony_ci
83062306a36Sopenharmony_ci	return_ACPI_STATUS(status);
83162306a36Sopenharmony_ci}
832