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