1*95857638SErik Schmauss // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
295b482a8SLen Brown /*******************************************************************************
395b482a8SLen Brown *
495b482a8SLen Brown * Module Name: dsutils - Dispatcher utilities
595b482a8SLen Brown *
695b482a8SLen Brown ******************************************************************************/
795b482a8SLen Brown
895b482a8SLen Brown #include <acpi/acpi.h>
9e2f7a777SLen Brown #include "accommon.h"
10e2f7a777SLen Brown #include "acparser.h"
11e2f7a777SLen Brown #include "amlcode.h"
12e2f7a777SLen Brown #include "acdispat.h"
13e2f7a777SLen Brown #include "acinterp.h"
14e2f7a777SLen Brown #include "acnamesp.h"
15e2f7a777SLen Brown #include "acdebug.h"
1695b482a8SLen Brown
1795b482a8SLen Brown #define _COMPONENT ACPI_DISPATCHER
1895b482a8SLen Brown ACPI_MODULE_NAME("dsutils")
1995b482a8SLen Brown
2095b482a8SLen Brown /*******************************************************************************
2195b482a8SLen Brown *
2295b482a8SLen Brown * FUNCTION: acpi_ds_clear_implicit_return
2395b482a8SLen Brown *
2495b482a8SLen Brown * PARAMETERS: walk_state - Current State
2595b482a8SLen Brown *
2695b482a8SLen Brown * RETURN: None.
2795b482a8SLen Brown *
2895b482a8SLen Brown * DESCRIPTION: Clear and remove a reference on an implicit return value. Used
2995b482a8SLen Brown * to delete "stale" return values (if enabled, the return value
3095b482a8SLen Brown * from every operator is saved at least momentarily, in case the
3195b482a8SLen Brown * parent method exits.)
3295b482a8SLen Brown *
3395b482a8SLen Brown ******************************************************************************/
acpi_ds_clear_implicit_return(struct acpi_walk_state * walk_state)3495b482a8SLen Brown void acpi_ds_clear_implicit_return(struct acpi_walk_state *walk_state)
3595b482a8SLen Brown {
3695b482a8SLen Brown ACPI_FUNCTION_NAME(ds_clear_implicit_return);
3795b482a8SLen Brown
3895b482a8SLen Brown /*
3995b482a8SLen Brown * Slack must be enabled for this feature
4095b482a8SLen Brown */
4195b482a8SLen Brown if (!acpi_gbl_enable_interpreter_slack) {
4295b482a8SLen Brown return;
4395b482a8SLen Brown }
4495b482a8SLen Brown
4595b482a8SLen Brown if (walk_state->implicit_return_obj) {
4695b482a8SLen Brown /*
4795b482a8SLen Brown * Delete any "stale" implicit return. However, in
4895b482a8SLen Brown * complex statements, the implicit return value can be
4995b482a8SLen Brown * bubbled up several levels.
5095b482a8SLen Brown */
5195b482a8SLen Brown ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
5295b482a8SLen Brown "Removing reference on stale implicit return obj %p\n",
5395b482a8SLen Brown walk_state->implicit_return_obj));
5495b482a8SLen Brown
5595b482a8SLen Brown acpi_ut_remove_reference(walk_state->implicit_return_obj);
5695b482a8SLen Brown walk_state->implicit_return_obj = NULL;
5795b482a8SLen Brown }
5895b482a8SLen Brown }
5995b482a8SLen Brown
6095b482a8SLen Brown /*******************************************************************************
6195b482a8SLen Brown *
6295b482a8SLen Brown * FUNCTION: acpi_ds_do_implicit_return
6395b482a8SLen Brown *
6495b482a8SLen Brown * PARAMETERS: return_desc - The return value
6595b482a8SLen Brown * walk_state - Current State
6695b482a8SLen Brown * add_reference - True if a reference should be added to the
6795b482a8SLen Brown * return object
6895b482a8SLen Brown *
6995b482a8SLen Brown * RETURN: TRUE if implicit return enabled, FALSE otherwise
7095b482a8SLen Brown *
7195b482a8SLen Brown * DESCRIPTION: Implements the optional "implicit return". We save the result
7295b482a8SLen Brown * of every ASL operator and control method invocation in case the
7395b482a8SLen Brown * parent method exit. Before storing a new return value, we
7495b482a8SLen Brown * delete the previous return value.
7595b482a8SLen Brown *
7695b482a8SLen Brown ******************************************************************************/
7795b482a8SLen Brown
7895b482a8SLen Brown u8
acpi_ds_do_implicit_return(union acpi_operand_object * return_desc,struct acpi_walk_state * walk_state,u8 add_reference)7995b482a8SLen Brown acpi_ds_do_implicit_return(union acpi_operand_object *return_desc,
8095b482a8SLen Brown struct acpi_walk_state *walk_state, u8 add_reference)
8195b482a8SLen Brown {
8295b482a8SLen Brown ACPI_FUNCTION_NAME(ds_do_implicit_return);
8395b482a8SLen Brown
8495b482a8SLen Brown /*
8595b482a8SLen Brown * Slack must be enabled for this feature, and we must
8695b482a8SLen Brown * have a valid return object
8795b482a8SLen Brown */
8895b482a8SLen Brown if ((!acpi_gbl_enable_interpreter_slack) || (!return_desc)) {
8995b482a8SLen Brown return (FALSE);
9095b482a8SLen Brown }
9195b482a8SLen Brown
9295b482a8SLen Brown ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
9395b482a8SLen Brown "Result %p will be implicitly returned; Prev=%p\n",
9495b482a8SLen Brown return_desc, walk_state->implicit_return_obj));
9595b482a8SLen Brown
9695b482a8SLen Brown /*
9795b482a8SLen Brown * Delete any "stale" implicit return value first. However, in
9895b482a8SLen Brown * complex statements, the implicit return value can be
9995b482a8SLen Brown * bubbled up several levels, so we don't clear the value if it
10095b482a8SLen Brown * is the same as the return_desc.
10195b482a8SLen Brown */
10295b482a8SLen Brown if (walk_state->implicit_return_obj) {
10395b482a8SLen Brown if (walk_state->implicit_return_obj == return_desc) {
10495b482a8SLen Brown return (TRUE);
10595b482a8SLen Brown }
10695b482a8SLen Brown acpi_ds_clear_implicit_return(walk_state);
10795b482a8SLen Brown }
10895b482a8SLen Brown
10995b482a8SLen Brown /* Save the implicit return value, add a reference if requested */
11095b482a8SLen Brown
11195b482a8SLen Brown walk_state->implicit_return_obj = return_desc;
11295b482a8SLen Brown if (add_reference) {
11395b482a8SLen Brown acpi_ut_add_reference(return_desc);
11495b482a8SLen Brown }
11595b482a8SLen Brown
11695b482a8SLen Brown return (TRUE);
11795b482a8SLen Brown }
11895b482a8SLen Brown
11995b482a8SLen Brown /*******************************************************************************
12095b482a8SLen Brown *
12195b482a8SLen Brown * FUNCTION: acpi_ds_is_result_used
12295b482a8SLen Brown *
123ba494beeSBob Moore * PARAMETERS: op - Current Op
12495b482a8SLen Brown * walk_state - Current State
12595b482a8SLen Brown *
12695b482a8SLen Brown * RETURN: TRUE if result is used, FALSE otherwise
12795b482a8SLen Brown *
12895b482a8SLen Brown * DESCRIPTION: Check if a result object will be used by the parent
12995b482a8SLen Brown *
13095b482a8SLen Brown ******************************************************************************/
13195b482a8SLen Brown
13295b482a8SLen Brown u8
acpi_ds_is_result_used(union acpi_parse_object * op,struct acpi_walk_state * walk_state)13395b482a8SLen Brown acpi_ds_is_result_used(union acpi_parse_object * op,
13495b482a8SLen Brown struct acpi_walk_state * walk_state)
13595b482a8SLen Brown {
13695b482a8SLen Brown const struct acpi_opcode_info *parent_info;
13795b482a8SLen Brown
13895b482a8SLen Brown ACPI_FUNCTION_TRACE_PTR(ds_is_result_used, op);
13995b482a8SLen Brown
14095b482a8SLen Brown /* Must have both an Op and a Result Object */
14195b482a8SLen Brown
14295b482a8SLen Brown if (!op) {
14395b482a8SLen Brown ACPI_ERROR((AE_INFO, "Null Op"));
144fd1af712SBob Moore return_UINT8(TRUE);
14595b482a8SLen Brown }
14695b482a8SLen Brown
14795b482a8SLen Brown /*
14895b482a8SLen Brown * We know that this operator is not a
14995b482a8SLen Brown * Return() operator (would not come here.) The following code is the
15095b482a8SLen Brown * optional support for a so-called "implicit return". Some AML code
15195b482a8SLen Brown * assumes that the last value of the method is "implicitly" returned
15295b482a8SLen Brown * to the caller. Just save the last result as the return value.
15395b482a8SLen Brown * NOTE: this is optional because the ASL language does not actually
15495b482a8SLen Brown * support this behavior.
15595b482a8SLen Brown */
15695b482a8SLen Brown (void)acpi_ds_do_implicit_return(walk_state->result_obj, walk_state,
15795b482a8SLen Brown TRUE);
15895b482a8SLen Brown
15995b482a8SLen Brown /*
16095b482a8SLen Brown * Now determine if the parent will use the result
16195b482a8SLen Brown *
16295b482a8SLen Brown * If there is no parent, or the parent is a scope_op, we are executing
16395b482a8SLen Brown * at the method level. An executing method typically has no parent,
16495b482a8SLen Brown * since each method is parsed separately. A method invoked externally
16595b482a8SLen Brown * via execute_control_method has a scope_op as the parent.
16695b482a8SLen Brown */
16795b482a8SLen Brown if ((!op->common.parent) ||
16895b482a8SLen Brown (op->common.parent->common.aml_opcode == AML_SCOPE_OP)) {
16995b482a8SLen Brown
17095b482a8SLen Brown /* No parent, the return value cannot possibly be used */
17195b482a8SLen Brown
17295b482a8SLen Brown ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
17395b482a8SLen Brown "At Method level, result of [%s] not used\n",
17495b482a8SLen Brown acpi_ps_get_opcode_name(op->common.
17595b482a8SLen Brown aml_opcode)));
176fd1af712SBob Moore return_UINT8(FALSE);
17795b482a8SLen Brown }
17895b482a8SLen Brown
17995b482a8SLen Brown /* Get info on the parent. The root_op is AML_SCOPE */
18095b482a8SLen Brown
18195b482a8SLen Brown parent_info =
18295b482a8SLen Brown acpi_ps_get_opcode_info(op->common.parent->common.aml_opcode);
18395b482a8SLen Brown if (parent_info->class == AML_CLASS_UNKNOWN) {
18495b482a8SLen Brown ACPI_ERROR((AE_INFO, "Unknown parent opcode Op=%p", op));
185fd1af712SBob Moore return_UINT8(FALSE);
18695b482a8SLen Brown }
18795b482a8SLen Brown
18895b482a8SLen Brown /*
18995b482a8SLen Brown * Decide what to do with the result based on the parent. If
19095b482a8SLen Brown * the parent opcode will not use the result, delete the object.
19195b482a8SLen Brown * Otherwise leave it as is, it will be deleted when it is used
19295b482a8SLen Brown * as an operand later.
19395b482a8SLen Brown */
19495b482a8SLen Brown switch (parent_info->class) {
19595b482a8SLen Brown case AML_CLASS_CONTROL:
19695b482a8SLen Brown
19795b482a8SLen Brown switch (op->common.parent->common.aml_opcode) {
19895b482a8SLen Brown case AML_RETURN_OP:
19995b482a8SLen Brown
20095b482a8SLen Brown /* Never delete the return value associated with a return opcode */
20195b482a8SLen Brown
20295b482a8SLen Brown goto result_used;
20395b482a8SLen Brown
20495b482a8SLen Brown case AML_IF_OP:
20595b482a8SLen Brown case AML_WHILE_OP:
20695b482a8SLen Brown /*
20795b482a8SLen Brown * If we are executing the predicate AND this is the predicate op,
20895b482a8SLen Brown * we will use the return value
20995b482a8SLen Brown */
21095b482a8SLen Brown if ((walk_state->control_state->common.state ==
2111fad8738SBob Moore ACPI_CONTROL_PREDICATE_EXECUTING) &&
2121fad8738SBob Moore (walk_state->control_state->control.predicate_op ==
2131fad8738SBob Moore op)) {
21495b482a8SLen Brown goto result_used;
21595b482a8SLen Brown }
21695b482a8SLen Brown break;
21795b482a8SLen Brown
21895b482a8SLen Brown default:
2191d1ea1b7SChao Guan
22095b482a8SLen Brown /* Ignore other control opcodes */
2211d1ea1b7SChao Guan
22295b482a8SLen Brown break;
22395b482a8SLen Brown }
22495b482a8SLen Brown
22595b482a8SLen Brown /* The general control opcode returns no result */
22695b482a8SLen Brown
22795b482a8SLen Brown goto result_not_used;
22895b482a8SLen Brown
22995b482a8SLen Brown case AML_CLASS_CREATE:
23095b482a8SLen Brown /*
23195b482a8SLen Brown * These opcodes allow term_arg(s) as operands and therefore
23295b482a8SLen Brown * the operands can be method calls. The result is used.
23395b482a8SLen Brown */
23495b482a8SLen Brown goto result_used;
23595b482a8SLen Brown
23695b482a8SLen Brown case AML_CLASS_NAMED_OBJECT:
23795b482a8SLen Brown
23895b482a8SLen Brown if ((op->common.parent->common.aml_opcode == AML_REGION_OP) ||
23995b482a8SLen Brown (op->common.parent->common.aml_opcode == AML_DATA_REGION_OP)
24095b482a8SLen Brown || (op->common.parent->common.aml_opcode == AML_PACKAGE_OP)
24195b482a8SLen Brown || (op->common.parent->common.aml_opcode == AML_BUFFER_OP)
24295b482a8SLen Brown || (op->common.parent->common.aml_opcode ==
2439ff5a21aSBob Moore AML_VARIABLE_PACKAGE_OP)
2449ff5a21aSBob Moore || (op->common.parent->common.aml_opcode ==
24595b482a8SLen Brown AML_INT_EVAL_SUBTREE_OP)
24695b482a8SLen Brown || (op->common.parent->common.aml_opcode ==
24795b482a8SLen Brown AML_BANK_FIELD_OP)) {
24895b482a8SLen Brown /*
24995b482a8SLen Brown * These opcodes allow term_arg(s) as operands and therefore
25095b482a8SLen Brown * the operands can be method calls. The result is used.
25195b482a8SLen Brown */
25295b482a8SLen Brown goto result_used;
25395b482a8SLen Brown }
25495b482a8SLen Brown
25595b482a8SLen Brown goto result_not_used;
25695b482a8SLen Brown
25795b482a8SLen Brown default:
25895b482a8SLen Brown /*
25995b482a8SLen Brown * In all other cases. the parent will actually use the return
26095b482a8SLen Brown * object, so keep it.
26195b482a8SLen Brown */
26295b482a8SLen Brown goto result_used;
26395b482a8SLen Brown }
26495b482a8SLen Brown
26595b482a8SLen Brown result_used:
26695b482a8SLen Brown ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
26795b482a8SLen Brown "Result of [%s] used by Parent [%s] Op=%p\n",
26895b482a8SLen Brown acpi_ps_get_opcode_name(op->common.aml_opcode),
26995b482a8SLen Brown acpi_ps_get_opcode_name(op->common.parent->common.
27095b482a8SLen Brown aml_opcode), op));
27195b482a8SLen Brown
272fd1af712SBob Moore return_UINT8(TRUE);
27395b482a8SLen Brown
27495b482a8SLen Brown result_not_used:
27595b482a8SLen Brown ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
27695b482a8SLen Brown "Result of [%s] not used by Parent [%s] Op=%p\n",
27795b482a8SLen Brown acpi_ps_get_opcode_name(op->common.aml_opcode),
27895b482a8SLen Brown acpi_ps_get_opcode_name(op->common.parent->common.
27995b482a8SLen Brown aml_opcode), op));
28095b482a8SLen Brown
281fd1af712SBob Moore return_UINT8(FALSE);
28295b482a8SLen Brown }
28395b482a8SLen Brown
28495b482a8SLen Brown /*******************************************************************************
28595b482a8SLen Brown *
28695b482a8SLen Brown * FUNCTION: acpi_ds_delete_result_if_not_used
28795b482a8SLen Brown *
288ba494beeSBob Moore * PARAMETERS: op - Current parse Op
28995b482a8SLen Brown * result_obj - Result of the operation
29095b482a8SLen Brown * walk_state - Current state
29195b482a8SLen Brown *
29295b482a8SLen Brown * RETURN: Status
29395b482a8SLen Brown *
29495b482a8SLen Brown * DESCRIPTION: Used after interpretation of an opcode. If there is an internal
29595b482a8SLen Brown * result descriptor, check if the parent opcode will actually use
29695b482a8SLen Brown * this result. If not, delete the result now so that it will
29795b482a8SLen Brown * not become orphaned.
29895b482a8SLen Brown *
29995b482a8SLen Brown ******************************************************************************/
30095b482a8SLen Brown
30195b482a8SLen Brown void
acpi_ds_delete_result_if_not_used(union acpi_parse_object * op,union acpi_operand_object * result_obj,struct acpi_walk_state * walk_state)30295b482a8SLen Brown acpi_ds_delete_result_if_not_used(union acpi_parse_object *op,
30395b482a8SLen Brown union acpi_operand_object *result_obj,
30495b482a8SLen Brown struct acpi_walk_state *walk_state)
30595b482a8SLen Brown {
30695b482a8SLen Brown union acpi_operand_object *obj_desc;
30795b482a8SLen Brown acpi_status status;
30895b482a8SLen Brown
30995b482a8SLen Brown ACPI_FUNCTION_TRACE_PTR(ds_delete_result_if_not_used, result_obj);
31095b482a8SLen Brown
31195b482a8SLen Brown if (!op) {
31295b482a8SLen Brown ACPI_ERROR((AE_INFO, "Null Op"));
31395b482a8SLen Brown return_VOID;
31495b482a8SLen Brown }
31595b482a8SLen Brown
31695b482a8SLen Brown if (!result_obj) {
31795b482a8SLen Brown return_VOID;
31895b482a8SLen Brown }
31995b482a8SLen Brown
32095b482a8SLen Brown if (!acpi_ds_is_result_used(op, walk_state)) {
32195b482a8SLen Brown
32295b482a8SLen Brown /* Must pop the result stack (obj_desc should be equal to result_obj) */
32395b482a8SLen Brown
32495b482a8SLen Brown status = acpi_ds_result_pop(&obj_desc, walk_state);
32595b482a8SLen Brown if (ACPI_SUCCESS(status)) {
32695b482a8SLen Brown acpi_ut_remove_reference(result_obj);
32795b482a8SLen Brown }
32895b482a8SLen Brown }
32995b482a8SLen Brown
33095b482a8SLen Brown return_VOID;
33195b482a8SLen Brown }
33295b482a8SLen Brown
33395b482a8SLen Brown /*******************************************************************************
33495b482a8SLen Brown *
33595b482a8SLen Brown * FUNCTION: acpi_ds_resolve_operands
33695b482a8SLen Brown *
33795b482a8SLen Brown * PARAMETERS: walk_state - Current walk state with operands on stack
33895b482a8SLen Brown *
33995b482a8SLen Brown * RETURN: Status
34095b482a8SLen Brown *
34195b482a8SLen Brown * DESCRIPTION: Resolve all operands to their values. Used to prepare
34295b482a8SLen Brown * arguments to a control method invocation (a call from one
34395b482a8SLen Brown * method to another.)
34495b482a8SLen Brown *
34595b482a8SLen Brown ******************************************************************************/
34695b482a8SLen Brown
acpi_ds_resolve_operands(struct acpi_walk_state * walk_state)34795b482a8SLen Brown acpi_status acpi_ds_resolve_operands(struct acpi_walk_state *walk_state)
34895b482a8SLen Brown {
34995b482a8SLen Brown u32 i;
35095b482a8SLen Brown acpi_status status = AE_OK;
35195b482a8SLen Brown
35295b482a8SLen Brown ACPI_FUNCTION_TRACE_PTR(ds_resolve_operands, walk_state);
35395b482a8SLen Brown
35495b482a8SLen Brown /*
35595b482a8SLen Brown * Attempt to resolve each of the valid operands
35695b482a8SLen Brown * Method arguments are passed by reference, not by value. This means
35795b482a8SLen Brown * that the actual objects are passed, not copies of the objects.
35895b482a8SLen Brown */
35995b482a8SLen Brown for (i = 0; i < walk_state->num_operands; i++) {
36095b482a8SLen Brown status =
36195b482a8SLen Brown acpi_ex_resolve_to_value(&walk_state->operands[i],
36295b482a8SLen Brown walk_state);
36395b482a8SLen Brown if (ACPI_FAILURE(status)) {
36495b482a8SLen Brown break;
36595b482a8SLen Brown }
36695b482a8SLen Brown }
36795b482a8SLen Brown
36895b482a8SLen Brown return_ACPI_STATUS(status);
36995b482a8SLen Brown }
37095b482a8SLen Brown
37195b482a8SLen Brown /*******************************************************************************
37295b482a8SLen Brown *
37395b482a8SLen Brown * FUNCTION: acpi_ds_clear_operands
37495b482a8SLen Brown *
37595b482a8SLen Brown * PARAMETERS: walk_state - Current walk state with operands on stack
37695b482a8SLen Brown *
37795b482a8SLen Brown * RETURN: None
37895b482a8SLen Brown *
37995b482a8SLen Brown * DESCRIPTION: Clear all operands on the current walk state operand stack.
38095b482a8SLen Brown *
38195b482a8SLen Brown ******************************************************************************/
38295b482a8SLen Brown
acpi_ds_clear_operands(struct acpi_walk_state * walk_state)38395b482a8SLen Brown void acpi_ds_clear_operands(struct acpi_walk_state *walk_state)
38495b482a8SLen Brown {
38595b482a8SLen Brown u32 i;
38695b482a8SLen Brown
38795b482a8SLen Brown ACPI_FUNCTION_TRACE_PTR(ds_clear_operands, walk_state);
38895b482a8SLen Brown
38995b482a8SLen Brown /* Remove a reference on each operand on the stack */
39095b482a8SLen Brown
39195b482a8SLen Brown for (i = 0; i < walk_state->num_operands; i++) {
39295b482a8SLen Brown /*
39395b482a8SLen Brown * Remove a reference to all operands, including both
39495b482a8SLen Brown * "Arguments" and "Targets".
39595b482a8SLen Brown */
39695b482a8SLen Brown acpi_ut_remove_reference(walk_state->operands[i]);
39795b482a8SLen Brown walk_state->operands[i] = NULL;
39895b482a8SLen Brown }
39995b482a8SLen Brown
40095b482a8SLen Brown walk_state->num_operands = 0;
40195b482a8SLen Brown return_VOID;
40295b482a8SLen Brown }
40395b482a8SLen Brown
40495b482a8SLen Brown /*******************************************************************************
40595b482a8SLen Brown *
40695b482a8SLen Brown * FUNCTION: acpi_ds_create_operand
40795b482a8SLen Brown *
40895b482a8SLen Brown * PARAMETERS: walk_state - Current walk state
409ba494beeSBob Moore * arg - Parse object for the argument
41095b482a8SLen Brown * arg_index - Which argument (zero based)
41195b482a8SLen Brown *
41295b482a8SLen Brown * RETURN: Status
41395b482a8SLen Brown *
41495b482a8SLen Brown * DESCRIPTION: Translate a parse tree object that is an argument to an AML
41595b482a8SLen Brown * opcode to the equivalent interpreter object. This may include
41695b482a8SLen Brown * looking up a name or entering a new name into the internal
41795b482a8SLen Brown * namespace.
41895b482a8SLen Brown *
41995b482a8SLen Brown ******************************************************************************/
42095b482a8SLen Brown
42195b482a8SLen Brown acpi_status
acpi_ds_create_operand(struct acpi_walk_state * walk_state,union acpi_parse_object * arg,u32 arg_index)42295b482a8SLen Brown acpi_ds_create_operand(struct acpi_walk_state *walk_state,
42395b482a8SLen Brown union acpi_parse_object *arg, u32 arg_index)
42495b482a8SLen Brown {
42595b482a8SLen Brown acpi_status status = AE_OK;
42695b482a8SLen Brown char *name_string;
42795b482a8SLen Brown u32 name_length;
42895b482a8SLen Brown union acpi_operand_object *obj_desc;
42995b482a8SLen Brown union acpi_parse_object *parent_op;
43095b482a8SLen Brown u16 opcode;
43195b482a8SLen Brown acpi_interpreter_mode interpreter_mode;
43295b482a8SLen Brown const struct acpi_opcode_info *op_info;
43395b482a8SLen Brown
43495b482a8SLen Brown ACPI_FUNCTION_TRACE_PTR(ds_create_operand, arg);
43595b482a8SLen Brown
43695b482a8SLen Brown /* A valid name must be looked up in the namespace */
43795b482a8SLen Brown
43895b482a8SLen Brown if ((arg->common.aml_opcode == AML_INT_NAMEPATH_OP) &&
43995b482a8SLen Brown (arg->common.value.string) &&
44095b482a8SLen Brown !(arg->common.flags & ACPI_PARSEOP_IN_STACK)) {
44195b482a8SLen Brown ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, "Getting a name: Arg=%p\n",
44295b482a8SLen Brown arg));
44395b482a8SLen Brown
44495b482a8SLen Brown /* Get the entire name string from the AML stream */
44595b482a8SLen Brown
4461fad8738SBob Moore status = acpi_ex_get_name_string(ACPI_TYPE_ANY,
44795b482a8SLen Brown arg->common.value.buffer,
44895b482a8SLen Brown &name_string, &name_length);
44995b482a8SLen Brown
45095b482a8SLen Brown if (ACPI_FAILURE(status)) {
45195b482a8SLen Brown return_ACPI_STATUS(status);
45295b482a8SLen Brown }
45395b482a8SLen Brown
45495b482a8SLen Brown /* All prefixes have been handled, and the name is in name_string */
45595b482a8SLen Brown
45695b482a8SLen Brown /*
45795b482a8SLen Brown * Special handling for buffer_field declarations. This is a deferred
45895b482a8SLen Brown * opcode that unfortunately defines the field name as the last
45995b482a8SLen Brown * parameter instead of the first. We get here when we are performing
46095b482a8SLen Brown * the deferred execution, so the actual name of the field is already
46195b482a8SLen Brown * in the namespace. We don't want to attempt to look it up again
46295b482a8SLen Brown * because we may be executing in a different scope than where the
46395b482a8SLen Brown * actual opcode exists.
46495b482a8SLen Brown */
46595b482a8SLen Brown if ((walk_state->deferred_node) &&
46695b482a8SLen Brown (walk_state->deferred_node->type == ACPI_TYPE_BUFFER_FIELD)
4671fad8738SBob Moore && (arg_index == (u32)
4681fad8738SBob Moore ((walk_state->opcode == AML_CREATE_FIELD_OP) ? 3 : 2))) {
46995b482a8SLen Brown obj_desc =
47095b482a8SLen Brown ACPI_CAST_PTR(union acpi_operand_object,
47195b482a8SLen Brown walk_state->deferred_node);
47295b482a8SLen Brown status = AE_OK;
47395b482a8SLen Brown } else { /* All other opcodes */
47495b482a8SLen Brown
47595b482a8SLen Brown /*
47695b482a8SLen Brown * Differentiate between a namespace "create" operation
47795b482a8SLen Brown * versus a "lookup" operation (IMODE_LOAD_PASS2 vs.
47895b482a8SLen Brown * IMODE_EXECUTE) in order to support the creation of
47995b482a8SLen Brown * namespace objects during the execution of control methods.
48095b482a8SLen Brown */
48195b482a8SLen Brown parent_op = arg->common.parent;
48295b482a8SLen Brown op_info =
48395b482a8SLen Brown acpi_ps_get_opcode_info(parent_op->common.
48495b482a8SLen Brown aml_opcode);
4851fad8738SBob Moore
4861fad8738SBob Moore if ((op_info->flags & AML_NSNODE) &&
4871fad8738SBob Moore (parent_op->common.aml_opcode !=
48895b482a8SLen Brown AML_INT_METHODCALL_OP)
48995b482a8SLen Brown && (parent_op->common.aml_opcode != AML_REGION_OP)
49095b482a8SLen Brown && (parent_op->common.aml_opcode !=
49195b482a8SLen Brown AML_INT_NAMEPATH_OP)) {
49295b482a8SLen Brown
49395b482a8SLen Brown /* Enter name into namespace if not found */
49495b482a8SLen Brown
49595b482a8SLen Brown interpreter_mode = ACPI_IMODE_LOAD_PASS2;
49695b482a8SLen Brown } else {
49795b482a8SLen Brown /* Return a failure if name not found */
49895b482a8SLen Brown
49995b482a8SLen Brown interpreter_mode = ACPI_IMODE_EXECUTE;
50095b482a8SLen Brown }
50195b482a8SLen Brown
50295b482a8SLen Brown status =
50395b482a8SLen Brown acpi_ns_lookup(walk_state->scope_info, name_string,
50495b482a8SLen Brown ACPI_TYPE_ANY, interpreter_mode,
50595b482a8SLen Brown ACPI_NS_SEARCH_PARENT |
50695b482a8SLen Brown ACPI_NS_DONT_OPEN_SCOPE, walk_state,
50795b482a8SLen Brown ACPI_CAST_INDIRECT_PTR(struct
50895b482a8SLen Brown acpi_namespace_node,
50995b482a8SLen Brown &obj_desc));
51095b482a8SLen Brown /*
51195b482a8SLen Brown * The only case where we pass through (ignore) a NOT_FOUND
51295b482a8SLen Brown * error is for the cond_ref_of opcode.
51395b482a8SLen Brown */
51495b482a8SLen Brown if (status == AE_NOT_FOUND) {
51595b482a8SLen Brown if (parent_op->common.aml_opcode ==
5169ff5a21aSBob Moore AML_CONDITIONAL_REF_OF_OP) {
51795b482a8SLen Brown /*
51895b482a8SLen Brown * For the Conditional Reference op, it's OK if
51995b482a8SLen Brown * the name is not found; We just need a way to
52095b482a8SLen Brown * indicate this to the interpreter, set the
52195b482a8SLen Brown * object to the root
52295b482a8SLen Brown */
5231f86e8c1SLv Zheng obj_desc =
5241f86e8c1SLv Zheng ACPI_CAST_PTR(union
52595b482a8SLen Brown acpi_operand_object,
52695b482a8SLen Brown acpi_gbl_root_node);
52795b482a8SLen Brown status = AE_OK;
52856a3d5e7SBob Moore } else if (parent_op->common.aml_opcode ==
52956a3d5e7SBob Moore AML_EXTERNAL_OP) {
5307fdb5ceaSBob Moore /*
5317fdb5ceaSBob Moore * This opcode should never appear here. It is used only
5327fdb5ceaSBob Moore * by AML disassemblers and is surrounded by an If(0)
5337fdb5ceaSBob Moore * by the ASL compiler.
5347fdb5ceaSBob Moore *
5357fdb5ceaSBob Moore * Therefore, if we see it here, it is a serious error.
5367fdb5ceaSBob Moore */
5377fdb5ceaSBob Moore status = AE_AML_BAD_OPCODE;
53895b482a8SLen Brown } else {
53995b482a8SLen Brown /*
54095b482a8SLen Brown * We just plain didn't find it -- which is a
54195b482a8SLen Brown * very serious error at this point
54295b482a8SLen Brown */
54395b482a8SLen Brown status = AE_AML_NAME_NOT_FOUND;
54495b482a8SLen Brown }
54595b482a8SLen Brown }
54695b482a8SLen Brown
54795b482a8SLen Brown if (ACPI_FAILURE(status)) {
54816ccf829SBob Moore ACPI_ERROR_NAMESPACE(walk_state->scope_info,
54916ccf829SBob Moore name_string, status);
55095b482a8SLen Brown }
55195b482a8SLen Brown }
55295b482a8SLen Brown
55395b482a8SLen Brown /* Free the namestring created above */
55495b482a8SLen Brown
55595b482a8SLen Brown ACPI_FREE(name_string);
55695b482a8SLen Brown
55795b482a8SLen Brown /* Check status from the lookup */
55895b482a8SLen Brown
55995b482a8SLen Brown if (ACPI_FAILURE(status)) {
56095b482a8SLen Brown return_ACPI_STATUS(status);
56195b482a8SLen Brown }
56295b482a8SLen Brown
56395b482a8SLen Brown /* Put the resulting object onto the current object stack */
56495b482a8SLen Brown
56595b482a8SLen Brown status = acpi_ds_obj_stack_push(obj_desc, walk_state);
56695b482a8SLen Brown if (ACPI_FAILURE(status)) {
56795b482a8SLen Brown return_ACPI_STATUS(status);
56895b482a8SLen Brown }
5698a2a2501SLv Zheng
5708a2a2501SLv Zheng acpi_db_display_argument_object(obj_desc, walk_state);
57195b482a8SLen Brown } else {
57295b482a8SLen Brown /* Check for null name case */
57395b482a8SLen Brown
57495b482a8SLen Brown if ((arg->common.aml_opcode == AML_INT_NAMEPATH_OP) &&
57595b482a8SLen Brown !(arg->common.flags & ACPI_PARSEOP_IN_STACK)) {
57695b482a8SLen Brown /*
57795b482a8SLen Brown * If the name is null, this means that this is an
57895b482a8SLen Brown * optional result parameter that was not specified
57995b482a8SLen Brown * in the original ASL. Create a Zero Constant for a
58095b482a8SLen Brown * placeholder. (Store to a constant is a Noop.)
58195b482a8SLen Brown */
58295b482a8SLen Brown opcode = AML_ZERO_OP; /* Has no arguments! */
58395b482a8SLen Brown
58495b482a8SLen Brown ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
58595b482a8SLen Brown "Null namepath: Arg=%p\n", arg));
58695b482a8SLen Brown } else {
58795b482a8SLen Brown opcode = arg->common.aml_opcode;
58895b482a8SLen Brown }
58995b482a8SLen Brown
59095b482a8SLen Brown /* Get the object type of the argument */
59195b482a8SLen Brown
59295b482a8SLen Brown op_info = acpi_ps_get_opcode_info(opcode);
59395b482a8SLen Brown if (op_info->object_type == ACPI_TYPE_INVALID) {
59495b482a8SLen Brown return_ACPI_STATUS(AE_NOT_IMPLEMENTED);
59595b482a8SLen Brown }
59695b482a8SLen Brown
5971fad8738SBob Moore if ((op_info->flags & AML_HAS_RETVAL) ||
5981fad8738SBob Moore (arg->common.flags & ACPI_PARSEOP_IN_STACK)) {
59995b482a8SLen Brown /*
60095b482a8SLen Brown * Use value that was already previously returned
60195b482a8SLen Brown * by the evaluation of this argument
60295b482a8SLen Brown */
60395b482a8SLen Brown status = acpi_ds_result_pop(&obj_desc, walk_state);
60495b482a8SLen Brown if (ACPI_FAILURE(status)) {
60595b482a8SLen Brown /*
60695b482a8SLen Brown * Only error is underflow, and this indicates
60795b482a8SLen Brown * a missing or null operand!
60895b482a8SLen Brown */
60995b482a8SLen Brown ACPI_EXCEPTION((AE_INFO, status,
61095b482a8SLen Brown "Missing or null operand"));
61195b482a8SLen Brown return_ACPI_STATUS(status);
61295b482a8SLen Brown }
61395b482a8SLen Brown } else {
61495b482a8SLen Brown /* Create an ACPI_INTERNAL_OBJECT for the argument */
61595b482a8SLen Brown
61695b482a8SLen Brown obj_desc =
61795b482a8SLen Brown acpi_ut_create_internal_object(op_info->
61895b482a8SLen Brown object_type);
61995b482a8SLen Brown if (!obj_desc) {
62095b482a8SLen Brown return_ACPI_STATUS(AE_NO_MEMORY);
62195b482a8SLen Brown }
62295b482a8SLen Brown
62395b482a8SLen Brown /* Initialize the new object */
62495b482a8SLen Brown
62595b482a8SLen Brown status =
62695b482a8SLen Brown acpi_ds_init_object_from_op(walk_state, arg, opcode,
62795b482a8SLen Brown &obj_desc);
62895b482a8SLen Brown if (ACPI_FAILURE(status)) {
62995b482a8SLen Brown acpi_ut_delete_object_desc(obj_desc);
63095b482a8SLen Brown return_ACPI_STATUS(status);
63195b482a8SLen Brown }
63295b482a8SLen Brown }
63395b482a8SLen Brown
63495b482a8SLen Brown /* Put the operand object on the object stack */
63595b482a8SLen Brown
63695b482a8SLen Brown status = acpi_ds_obj_stack_push(obj_desc, walk_state);
63795b482a8SLen Brown if (ACPI_FAILURE(status)) {
63895b482a8SLen Brown return_ACPI_STATUS(status);
63995b482a8SLen Brown }
64095b482a8SLen Brown
6418a2a2501SLv Zheng acpi_db_display_argument_object(obj_desc, walk_state);
64295b482a8SLen Brown }
64395b482a8SLen Brown
64495b482a8SLen Brown return_ACPI_STATUS(AE_OK);
64595b482a8SLen Brown }
64695b482a8SLen Brown
64795b482a8SLen Brown /*******************************************************************************
64895b482a8SLen Brown *
64995b482a8SLen Brown * FUNCTION: acpi_ds_create_operands
65095b482a8SLen Brown *
65195b482a8SLen Brown * PARAMETERS: walk_state - Current state
65295b482a8SLen Brown * first_arg - First argument of a parser argument tree
65395b482a8SLen Brown *
65495b482a8SLen Brown * RETURN: Status
65595b482a8SLen Brown *
65695b482a8SLen Brown * DESCRIPTION: Convert an operator's arguments from a parse tree format to
65795b482a8SLen Brown * namespace objects and place those argument object on the object
65895b482a8SLen Brown * stack in preparation for evaluation by the interpreter.
65995b482a8SLen Brown *
66095b482a8SLen Brown ******************************************************************************/
66195b482a8SLen Brown
66295b482a8SLen Brown acpi_status
acpi_ds_create_operands(struct acpi_walk_state * walk_state,union acpi_parse_object * first_arg)66395b482a8SLen Brown acpi_ds_create_operands(struct acpi_walk_state *walk_state,
66495b482a8SLen Brown union acpi_parse_object *first_arg)
66595b482a8SLen Brown {
66695b482a8SLen Brown acpi_status status = AE_OK;
66795b482a8SLen Brown union acpi_parse_object *arg;
66895b482a8SLen Brown union acpi_parse_object *arguments[ACPI_OBJ_NUM_OPERANDS];
66995b482a8SLen Brown u32 arg_count = 0;
67095b482a8SLen Brown u32 index = walk_state->num_operands;
67195b482a8SLen Brown u32 i;
67295b482a8SLen Brown
67395b482a8SLen Brown ACPI_FUNCTION_TRACE_PTR(ds_create_operands, first_arg);
67495b482a8SLen Brown
67595b482a8SLen Brown /* Get all arguments in the list */
67695b482a8SLen Brown
67795b482a8SLen Brown arg = first_arg;
67895b482a8SLen Brown while (arg) {
67995b482a8SLen Brown if (index >= ACPI_OBJ_NUM_OPERANDS) {
68095b482a8SLen Brown return_ACPI_STATUS(AE_BAD_DATA);
68195b482a8SLen Brown }
68295b482a8SLen Brown
68395b482a8SLen Brown arguments[index] = arg;
68495b482a8SLen Brown walk_state->operands[index] = NULL;
68595b482a8SLen Brown
68695b482a8SLen Brown /* Move on to next argument, if any */
68795b482a8SLen Brown
68895b482a8SLen Brown arg = arg->common.next;
68995b482a8SLen Brown arg_count++;
69095b482a8SLen Brown index++;
69195b482a8SLen Brown }
69295b482a8SLen Brown
69387beb7e8SBob Moore ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
69487beb7e8SBob Moore "NumOperands %d, ArgCount %d, Index %d\n",
69587beb7e8SBob Moore walk_state->num_operands, arg_count, index));
69687beb7e8SBob Moore
69787beb7e8SBob Moore /* Create the interpreter arguments, in reverse order */
69887beb7e8SBob Moore
69995b482a8SLen Brown index--;
70095b482a8SLen Brown for (i = 0; i < arg_count; i++) {
70195b482a8SLen Brown arg = arguments[index];
70295b482a8SLen Brown walk_state->operand_index = (u8)index;
70395b482a8SLen Brown
70495b482a8SLen Brown status = acpi_ds_create_operand(walk_state, arg, index);
70595b482a8SLen Brown if (ACPI_FAILURE(status)) {
70695b482a8SLen Brown goto cleanup;
70795b482a8SLen Brown }
70895b482a8SLen Brown
70995b482a8SLen Brown ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
71087beb7e8SBob Moore "Created Arg #%u (%p) %u args total\n",
71187beb7e8SBob Moore index, arg, arg_count));
71287beb7e8SBob Moore index--;
71395b482a8SLen Brown }
71495b482a8SLen Brown
71595b482a8SLen Brown return_ACPI_STATUS(status);
71695b482a8SLen Brown
71795b482a8SLen Brown cleanup:
71895b482a8SLen Brown /*
71995b482a8SLen Brown * We must undo everything done above; meaning that we must
72095b482a8SLen Brown * pop everything off of the operand stack and delete those
72195b482a8SLen Brown * objects
72295b482a8SLen Brown */
72395b482a8SLen Brown acpi_ds_obj_stack_pop_and_delete(arg_count, walk_state);
72495b482a8SLen Brown
725b27d6597SBob Moore ACPI_EXCEPTION((AE_INFO, status, "While creating Arg %u", index));
72695b482a8SLen Brown return_ACPI_STATUS(status);
72795b482a8SLen Brown }
72895b482a8SLen Brown
72995b482a8SLen Brown /*****************************************************************************
73095b482a8SLen Brown *
73195b482a8SLen Brown * FUNCTION: acpi_ds_evaluate_name_path
73295b482a8SLen Brown *
73395b482a8SLen Brown * PARAMETERS: walk_state - Current state of the parse tree walk,
73495b482a8SLen Brown * the opcode of current operation should be
73595b482a8SLen Brown * AML_INT_NAMEPATH_OP
73695b482a8SLen Brown *
73795b482a8SLen Brown * RETURN: Status
73895b482a8SLen Brown *
73995b482a8SLen Brown * DESCRIPTION: Translate the -name_path- parse tree object to the equivalent
74095b482a8SLen Brown * interpreter object, convert it to value, if needed, duplicate
74195b482a8SLen Brown * it, if needed, and push it onto the current result stack.
74295b482a8SLen Brown *
74395b482a8SLen Brown ****************************************************************************/
74495b482a8SLen Brown
acpi_ds_evaluate_name_path(struct acpi_walk_state * walk_state)74595b482a8SLen Brown acpi_status acpi_ds_evaluate_name_path(struct acpi_walk_state *walk_state)
74695b482a8SLen Brown {
74795b482a8SLen Brown acpi_status status = AE_OK;
74895b482a8SLen Brown union acpi_parse_object *op = walk_state->op;
74995b482a8SLen Brown union acpi_operand_object **operand = &walk_state->operands[0];
75095b482a8SLen Brown union acpi_operand_object *new_obj_desc;
75195b482a8SLen Brown u8 type;
75295b482a8SLen Brown
75395b482a8SLen Brown ACPI_FUNCTION_TRACE_PTR(ds_evaluate_name_path, walk_state);
75495b482a8SLen Brown
75595b482a8SLen Brown if (!op->common.parent) {
75695b482a8SLen Brown
75795b482a8SLen Brown /* This happens after certain exception processing */
75895b482a8SLen Brown
75995b482a8SLen Brown goto exit;
76095b482a8SLen Brown }
76195b482a8SLen Brown
76295b482a8SLen Brown if ((op->common.parent->common.aml_opcode == AML_PACKAGE_OP) ||
7639ff5a21aSBob Moore (op->common.parent->common.aml_opcode == AML_VARIABLE_PACKAGE_OP) ||
76495b482a8SLen Brown (op->common.parent->common.aml_opcode == AML_REF_OF_OP)) {
76595b482a8SLen Brown
76695b482a8SLen Brown /* TBD: Should we specify this feature as a bit of op_info->Flags of these opcodes? */
76795b482a8SLen Brown
76895b482a8SLen Brown goto exit;
76995b482a8SLen Brown }
77095b482a8SLen Brown
77195b482a8SLen Brown status = acpi_ds_create_operand(walk_state, op, 0);
77295b482a8SLen Brown if (ACPI_FAILURE(status)) {
77395b482a8SLen Brown goto exit;
77495b482a8SLen Brown }
77595b482a8SLen Brown
77695b482a8SLen Brown if (op->common.flags & ACPI_PARSEOP_TARGET) {
77795b482a8SLen Brown new_obj_desc = *operand;
77895b482a8SLen Brown goto push_result;
77995b482a8SLen Brown }
78095b482a8SLen Brown
7813371c19cSBob Moore type = (*operand)->common.type;
78295b482a8SLen Brown
78395b482a8SLen Brown status = acpi_ex_resolve_to_value(operand, walk_state);
78495b482a8SLen Brown if (ACPI_FAILURE(status)) {
78595b482a8SLen Brown goto exit;
78695b482a8SLen Brown }
78795b482a8SLen Brown
78895b482a8SLen Brown if (type == ACPI_TYPE_INTEGER) {
78995b482a8SLen Brown
79095b482a8SLen Brown /* It was incremented by acpi_ex_resolve_to_value */
79195b482a8SLen Brown
79295b482a8SLen Brown acpi_ut_remove_reference(*operand);
79395b482a8SLen Brown
79495b482a8SLen Brown status =
79595b482a8SLen Brown acpi_ut_copy_iobject_to_iobject(*operand, &new_obj_desc,
79695b482a8SLen Brown walk_state);
79795b482a8SLen Brown if (ACPI_FAILURE(status)) {
79895b482a8SLen Brown goto exit;
79995b482a8SLen Brown }
80095b482a8SLen Brown } else {
80195b482a8SLen Brown /*
80295b482a8SLen Brown * The object either was anew created or is
80395b482a8SLen Brown * a Namespace node - don't decrement it.
80495b482a8SLen Brown */
80595b482a8SLen Brown new_obj_desc = *operand;
80695b482a8SLen Brown }
80795b482a8SLen Brown
80895b482a8SLen Brown /* Cleanup for name-path operand */
80995b482a8SLen Brown
81095b482a8SLen Brown status = acpi_ds_obj_stack_pop(1, walk_state);
81195b482a8SLen Brown if (ACPI_FAILURE(status)) {
81295b482a8SLen Brown walk_state->result_obj = new_obj_desc;
81395b482a8SLen Brown goto exit;
81495b482a8SLen Brown }
81595b482a8SLen Brown
81695b482a8SLen Brown push_result:
81795b482a8SLen Brown
81895b482a8SLen Brown walk_state->result_obj = new_obj_desc;
81995b482a8SLen Brown
82095b482a8SLen Brown status = acpi_ds_result_push(walk_state->result_obj, walk_state);
82195b482a8SLen Brown if (ACPI_SUCCESS(status)) {
82295b482a8SLen Brown
82395b482a8SLen Brown /* Force to take it from stack */
82495b482a8SLen Brown
82595b482a8SLen Brown op->common.flags |= ACPI_PARSEOP_IN_STACK;
82695b482a8SLen Brown }
82795b482a8SLen Brown
82895b482a8SLen Brown exit:
82995b482a8SLen Brown
83095b482a8SLen Brown return_ACPI_STATUS(status);
83195b482a8SLen Brown }
832