162306a36Sopenharmony_ci// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 262306a36Sopenharmony_ci/****************************************************************************** 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Module Name: dswexec - Dispatcher method execution callbacks; 562306a36Sopenharmony_ci * dispatch to interpreter. 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Copyright (C) 2000 - 2023, Intel Corp. 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci *****************************************************************************/ 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include <acpi/acpi.h> 1262306a36Sopenharmony_ci#include "accommon.h" 1362306a36Sopenharmony_ci#include "acparser.h" 1462306a36Sopenharmony_ci#include "amlcode.h" 1562306a36Sopenharmony_ci#include "acdispat.h" 1662306a36Sopenharmony_ci#include "acinterp.h" 1762306a36Sopenharmony_ci#include "acnamesp.h" 1862306a36Sopenharmony_ci#include "acdebug.h" 1962306a36Sopenharmony_ci#ifdef ACPI_EXEC_APP 2062306a36Sopenharmony_ci#include "aecommon.h" 2162306a36Sopenharmony_ci#endif 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci#define _COMPONENT ACPI_DISPATCHER 2462306a36Sopenharmony_ciACPI_MODULE_NAME("dswexec") 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci/* 2762306a36Sopenharmony_ci * Dispatch table for opcode classes 2862306a36Sopenharmony_ci */ 2962306a36Sopenharmony_cistatic acpi_execute_op acpi_gbl_op_type_dispatch[] = { 3062306a36Sopenharmony_ci acpi_ex_opcode_0A_0T_1R, 3162306a36Sopenharmony_ci acpi_ex_opcode_1A_0T_0R, 3262306a36Sopenharmony_ci acpi_ex_opcode_1A_0T_1R, 3362306a36Sopenharmony_ci NULL, /* Was: acpi_ex_opcode_1A_0T_0R (Was for Load operator) */ 3462306a36Sopenharmony_ci acpi_ex_opcode_1A_1T_1R, 3562306a36Sopenharmony_ci acpi_ex_opcode_2A_0T_0R, 3662306a36Sopenharmony_ci acpi_ex_opcode_2A_0T_1R, 3762306a36Sopenharmony_ci acpi_ex_opcode_2A_1T_1R, 3862306a36Sopenharmony_ci acpi_ex_opcode_2A_2T_1R, 3962306a36Sopenharmony_ci acpi_ex_opcode_3A_0T_0R, 4062306a36Sopenharmony_ci acpi_ex_opcode_3A_1T_1R, 4162306a36Sopenharmony_ci acpi_ex_opcode_6A_0T_1R 4262306a36Sopenharmony_ci}; 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci/***************************************************************************** 4562306a36Sopenharmony_ci * 4662306a36Sopenharmony_ci * FUNCTION: acpi_ds_get_predicate_value 4762306a36Sopenharmony_ci * 4862306a36Sopenharmony_ci * PARAMETERS: walk_state - Current state of the parse tree walk 4962306a36Sopenharmony_ci * result_obj - if non-zero, pop result from result stack 5062306a36Sopenharmony_ci * 5162306a36Sopenharmony_ci * RETURN: Status 5262306a36Sopenharmony_ci * 5362306a36Sopenharmony_ci * DESCRIPTION: Get the result of a predicate evaluation 5462306a36Sopenharmony_ci * 5562306a36Sopenharmony_ci ****************************************************************************/ 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ciacpi_status 5862306a36Sopenharmony_ciacpi_ds_get_predicate_value(struct acpi_walk_state *walk_state, 5962306a36Sopenharmony_ci union acpi_operand_object *result_obj) 6062306a36Sopenharmony_ci{ 6162306a36Sopenharmony_ci acpi_status status = AE_OK; 6262306a36Sopenharmony_ci union acpi_operand_object *obj_desc; 6362306a36Sopenharmony_ci union acpi_operand_object *local_obj_desc = NULL; 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci ACPI_FUNCTION_TRACE_PTR(ds_get_predicate_value, walk_state); 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci walk_state->control_state->common.state = 0; 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci if (result_obj) { 7062306a36Sopenharmony_ci status = acpi_ds_result_pop(&obj_desc, walk_state); 7162306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 7262306a36Sopenharmony_ci ACPI_EXCEPTION((AE_INFO, status, 7362306a36Sopenharmony_ci "Could not get result from predicate evaluation")); 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci return_ACPI_STATUS(status); 7662306a36Sopenharmony_ci } 7762306a36Sopenharmony_ci } else { 7862306a36Sopenharmony_ci status = acpi_ds_create_operand(walk_state, walk_state->op, 0); 7962306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 8062306a36Sopenharmony_ci return_ACPI_STATUS(status); 8162306a36Sopenharmony_ci } 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci status = 8462306a36Sopenharmony_ci acpi_ex_resolve_to_value(&walk_state->operands[0], 8562306a36Sopenharmony_ci walk_state); 8662306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 8762306a36Sopenharmony_ci return_ACPI_STATUS(status); 8862306a36Sopenharmony_ci } 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci obj_desc = walk_state->operands[0]; 9162306a36Sopenharmony_ci } 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci if (!obj_desc) { 9462306a36Sopenharmony_ci ACPI_ERROR((AE_INFO, 9562306a36Sopenharmony_ci "No predicate ObjDesc=%p State=%p", 9662306a36Sopenharmony_ci obj_desc, walk_state)); 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci return_ACPI_STATUS(AE_AML_NO_OPERAND); 9962306a36Sopenharmony_ci } 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci /* 10262306a36Sopenharmony_ci * Result of predicate evaluation must be an Integer 10362306a36Sopenharmony_ci * object. Implicitly convert the argument if necessary. 10462306a36Sopenharmony_ci */ 10562306a36Sopenharmony_ci status = acpi_ex_convert_to_integer(obj_desc, &local_obj_desc, 10662306a36Sopenharmony_ci ACPI_IMPLICIT_CONVERSION); 10762306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 10862306a36Sopenharmony_ci goto cleanup; 10962306a36Sopenharmony_ci } 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci if (local_obj_desc->common.type != ACPI_TYPE_INTEGER) { 11262306a36Sopenharmony_ci ACPI_ERROR((AE_INFO, 11362306a36Sopenharmony_ci "Bad predicate (not an integer) ObjDesc=%p State=%p Type=0x%X", 11462306a36Sopenharmony_ci obj_desc, walk_state, obj_desc->common.type)); 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci status = AE_AML_OPERAND_TYPE; 11762306a36Sopenharmony_ci goto cleanup; 11862306a36Sopenharmony_ci } 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci /* Truncate the predicate to 32-bits if necessary */ 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci (void)acpi_ex_truncate_for32bit_table(local_obj_desc); 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci /* 12562306a36Sopenharmony_ci * Save the result of the predicate evaluation on 12662306a36Sopenharmony_ci * the control stack 12762306a36Sopenharmony_ci */ 12862306a36Sopenharmony_ci if (local_obj_desc->integer.value) { 12962306a36Sopenharmony_ci walk_state->control_state->common.value = TRUE; 13062306a36Sopenharmony_ci } else { 13162306a36Sopenharmony_ci /* 13262306a36Sopenharmony_ci * Predicate is FALSE, we will just toss the 13362306a36Sopenharmony_ci * rest of the package 13462306a36Sopenharmony_ci */ 13562306a36Sopenharmony_ci walk_state->control_state->common.value = FALSE; 13662306a36Sopenharmony_ci status = AE_CTRL_FALSE; 13762306a36Sopenharmony_ci } 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci /* Predicate can be used for an implicit return value */ 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci (void)acpi_ds_do_implicit_return(local_obj_desc, walk_state, TRUE); 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_cicleanup: 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci ACPI_DEBUG_PRINT((ACPI_DB_EXEC, 14662306a36Sopenharmony_ci "Completed a predicate eval=%X Op=%p\n", 14762306a36Sopenharmony_ci walk_state->control_state->common.value, 14862306a36Sopenharmony_ci walk_state->op)); 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci /* Break to debugger to display result */ 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci acpi_db_display_result_object(local_obj_desc, walk_state); 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci /* 15562306a36Sopenharmony_ci * Delete the predicate result object (we know that 15662306a36Sopenharmony_ci * we don't need it anymore) 15762306a36Sopenharmony_ci */ 15862306a36Sopenharmony_ci if (local_obj_desc != obj_desc) { 15962306a36Sopenharmony_ci acpi_ut_remove_reference(local_obj_desc); 16062306a36Sopenharmony_ci } 16162306a36Sopenharmony_ci acpi_ut_remove_reference(obj_desc); 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci walk_state->control_state->common.state = ACPI_CONTROL_NORMAL; 16462306a36Sopenharmony_ci return_ACPI_STATUS(status); 16562306a36Sopenharmony_ci} 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci/***************************************************************************** 16862306a36Sopenharmony_ci * 16962306a36Sopenharmony_ci * FUNCTION: acpi_ds_exec_begin_op 17062306a36Sopenharmony_ci * 17162306a36Sopenharmony_ci * PARAMETERS: walk_state - Current state of the parse tree walk 17262306a36Sopenharmony_ci * out_op - Where to return op if a new one is created 17362306a36Sopenharmony_ci * 17462306a36Sopenharmony_ci * RETURN: Status 17562306a36Sopenharmony_ci * 17662306a36Sopenharmony_ci * DESCRIPTION: Descending callback used during the execution of control 17762306a36Sopenharmony_ci * methods. This is where most operators and operands are 17862306a36Sopenharmony_ci * dispatched to the interpreter. 17962306a36Sopenharmony_ci * 18062306a36Sopenharmony_ci ****************************************************************************/ 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ciacpi_status 18362306a36Sopenharmony_ciacpi_ds_exec_begin_op(struct acpi_walk_state *walk_state, 18462306a36Sopenharmony_ci union acpi_parse_object **out_op) 18562306a36Sopenharmony_ci{ 18662306a36Sopenharmony_ci union acpi_parse_object *op; 18762306a36Sopenharmony_ci acpi_status status = AE_OK; 18862306a36Sopenharmony_ci u32 opcode_class; 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci ACPI_FUNCTION_TRACE_PTR(ds_exec_begin_op, walk_state); 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci op = walk_state->op; 19362306a36Sopenharmony_ci if (!op) { 19462306a36Sopenharmony_ci status = acpi_ds_load2_begin_op(walk_state, out_op); 19562306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 19662306a36Sopenharmony_ci goto error_exit; 19762306a36Sopenharmony_ci } 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci op = *out_op; 20062306a36Sopenharmony_ci walk_state->op = op; 20162306a36Sopenharmony_ci walk_state->opcode = op->common.aml_opcode; 20262306a36Sopenharmony_ci walk_state->op_info = 20362306a36Sopenharmony_ci acpi_ps_get_opcode_info(op->common.aml_opcode); 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci if (acpi_ns_opens_scope(walk_state->op_info->object_type)) { 20662306a36Sopenharmony_ci ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, 20762306a36Sopenharmony_ci "(%s) Popping scope for Op %p\n", 20862306a36Sopenharmony_ci acpi_ut_get_type_name(walk_state-> 20962306a36Sopenharmony_ci op_info-> 21062306a36Sopenharmony_ci object_type), 21162306a36Sopenharmony_ci op)); 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci status = acpi_ds_scope_stack_pop(walk_state); 21462306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 21562306a36Sopenharmony_ci goto error_exit; 21662306a36Sopenharmony_ci } 21762306a36Sopenharmony_ci } 21862306a36Sopenharmony_ci } 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci if (op == walk_state->origin) { 22162306a36Sopenharmony_ci if (out_op) { 22262306a36Sopenharmony_ci *out_op = op; 22362306a36Sopenharmony_ci } 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci return_ACPI_STATUS(AE_OK); 22662306a36Sopenharmony_ci } 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci /* 22962306a36Sopenharmony_ci * If the previous opcode was a conditional, this opcode 23062306a36Sopenharmony_ci * must be the beginning of the associated predicate. 23162306a36Sopenharmony_ci * Save this knowledge in the current scope descriptor 23262306a36Sopenharmony_ci */ 23362306a36Sopenharmony_ci if ((walk_state->control_state) && 23462306a36Sopenharmony_ci (walk_state->control_state->common.state == 23562306a36Sopenharmony_ci ACPI_CONTROL_CONDITIONAL_EXECUTING)) { 23662306a36Sopenharmony_ci ACPI_DEBUG_PRINT((ACPI_DB_EXEC, 23762306a36Sopenharmony_ci "Exec predicate Op=%p State=%p\n", 23862306a36Sopenharmony_ci op, walk_state)); 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci walk_state->control_state->common.state = 24162306a36Sopenharmony_ci ACPI_CONTROL_PREDICATE_EXECUTING; 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci /* Save start of predicate */ 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci walk_state->control_state->control.predicate_op = op; 24662306a36Sopenharmony_ci } 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci opcode_class = walk_state->op_info->class; 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci /* We want to send namepaths to the load code */ 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci if (op->common.aml_opcode == AML_INT_NAMEPATH_OP) { 25362306a36Sopenharmony_ci opcode_class = AML_CLASS_NAMED_OBJECT; 25462306a36Sopenharmony_ci } 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci /* 25762306a36Sopenharmony_ci * Handle the opcode based upon the opcode type 25862306a36Sopenharmony_ci */ 25962306a36Sopenharmony_ci switch (opcode_class) { 26062306a36Sopenharmony_ci case AML_CLASS_CONTROL: 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci status = acpi_ds_exec_begin_control_op(walk_state, op); 26362306a36Sopenharmony_ci break; 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci case AML_CLASS_NAMED_OBJECT: 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci if (walk_state->walk_type & ACPI_WALK_METHOD) { 26862306a36Sopenharmony_ci /* 26962306a36Sopenharmony_ci * Found a named object declaration during method execution; 27062306a36Sopenharmony_ci * we must enter this object into the namespace. The created 27162306a36Sopenharmony_ci * object is temporary and will be deleted upon completion of 27262306a36Sopenharmony_ci * the execution of this method. 27362306a36Sopenharmony_ci * 27462306a36Sopenharmony_ci * Note 10/2010: Except for the Scope() op. This opcode does 27562306a36Sopenharmony_ci * not actually create a new object, it refers to an existing 27662306a36Sopenharmony_ci * object. However, for Scope(), we want to indeed open a 27762306a36Sopenharmony_ci * new scope. 27862306a36Sopenharmony_ci */ 27962306a36Sopenharmony_ci if (op->common.aml_opcode != AML_SCOPE_OP) { 28062306a36Sopenharmony_ci status = 28162306a36Sopenharmony_ci acpi_ds_load2_begin_op(walk_state, NULL); 28262306a36Sopenharmony_ci } else { 28362306a36Sopenharmony_ci status = 28462306a36Sopenharmony_ci acpi_ds_scope_stack_push(op->named.node, 28562306a36Sopenharmony_ci op->named.node-> 28662306a36Sopenharmony_ci type, walk_state); 28762306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 28862306a36Sopenharmony_ci return_ACPI_STATUS(status); 28962306a36Sopenharmony_ci } 29062306a36Sopenharmony_ci } 29162306a36Sopenharmony_ci } 29262306a36Sopenharmony_ci break; 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci case AML_CLASS_EXECUTE: 29562306a36Sopenharmony_ci case AML_CLASS_CREATE: 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci break; 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci default: 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci break; 30262306a36Sopenharmony_ci } 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci /* Nothing to do here during method execution */ 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci return_ACPI_STATUS(status); 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_cierror_exit: 30962306a36Sopenharmony_ci status = acpi_ds_method_error(status, walk_state); 31062306a36Sopenharmony_ci return_ACPI_STATUS(status); 31162306a36Sopenharmony_ci} 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci/***************************************************************************** 31462306a36Sopenharmony_ci * 31562306a36Sopenharmony_ci * FUNCTION: acpi_ds_exec_end_op 31662306a36Sopenharmony_ci * 31762306a36Sopenharmony_ci * PARAMETERS: walk_state - Current state of the parse tree walk 31862306a36Sopenharmony_ci * 31962306a36Sopenharmony_ci * RETURN: Status 32062306a36Sopenharmony_ci * 32162306a36Sopenharmony_ci * DESCRIPTION: Ascending callback used during the execution of control 32262306a36Sopenharmony_ci * methods. The only thing we really need to do here is to 32362306a36Sopenharmony_ci * notice the beginning of IF, ELSE, and WHILE blocks. 32462306a36Sopenharmony_ci * 32562306a36Sopenharmony_ci ****************************************************************************/ 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ciacpi_status acpi_ds_exec_end_op(struct acpi_walk_state *walk_state) 32862306a36Sopenharmony_ci{ 32962306a36Sopenharmony_ci union acpi_parse_object *op; 33062306a36Sopenharmony_ci acpi_status status = AE_OK; 33162306a36Sopenharmony_ci u32 op_type; 33262306a36Sopenharmony_ci u32 op_class; 33362306a36Sopenharmony_ci union acpi_parse_object *next_op; 33462306a36Sopenharmony_ci union acpi_parse_object *first_arg; 33562306a36Sopenharmony_ci#ifdef ACPI_EXEC_APP 33662306a36Sopenharmony_ci char *namepath; 33762306a36Sopenharmony_ci union acpi_operand_object *obj_desc; 33862306a36Sopenharmony_ci#endif 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci ACPI_FUNCTION_TRACE_PTR(ds_exec_end_op, walk_state); 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci op = walk_state->op; 34362306a36Sopenharmony_ci op_type = walk_state->op_info->type; 34462306a36Sopenharmony_ci op_class = walk_state->op_info->class; 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci if (op_class == AML_CLASS_UNKNOWN) { 34762306a36Sopenharmony_ci ACPI_ERROR((AE_INFO, "Unknown opcode 0x%X", 34862306a36Sopenharmony_ci op->common.aml_opcode)); 34962306a36Sopenharmony_ci return_ACPI_STATUS(AE_NOT_IMPLEMENTED); 35062306a36Sopenharmony_ci } 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci first_arg = op->common.value.arg; 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci /* Init the walk state */ 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci walk_state->num_operands = 0; 35762306a36Sopenharmony_ci walk_state->operand_index = 0; 35862306a36Sopenharmony_ci walk_state->return_desc = NULL; 35962306a36Sopenharmony_ci walk_state->result_obj = NULL; 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci /* Call debugger for single step support (DEBUG build only) */ 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci status = acpi_db_single_step(walk_state, op, op_class); 36462306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 36562306a36Sopenharmony_ci return_ACPI_STATUS(status); 36662306a36Sopenharmony_ci } 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci /* Decode the Opcode Class */ 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci switch (op_class) { 37162306a36Sopenharmony_ci case AML_CLASS_ARGUMENT: /* Constants, literals, etc. */ 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci if (walk_state->opcode == AML_INT_NAMEPATH_OP) { 37462306a36Sopenharmony_ci status = acpi_ds_evaluate_name_path(walk_state); 37562306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 37662306a36Sopenharmony_ci goto cleanup; 37762306a36Sopenharmony_ci } 37862306a36Sopenharmony_ci } 37962306a36Sopenharmony_ci break; 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci case AML_CLASS_EXECUTE: /* Most operators with arguments */ 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci /* Build resolved operand stack */ 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci status = acpi_ds_create_operands(walk_state, first_arg); 38662306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 38762306a36Sopenharmony_ci goto cleanup; 38862306a36Sopenharmony_ci } 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci /* 39162306a36Sopenharmony_ci * All opcodes require operand resolution, with the only exceptions 39262306a36Sopenharmony_ci * being the object_type and size_of operators as well as opcodes that 39362306a36Sopenharmony_ci * take no arguments. 39462306a36Sopenharmony_ci */ 39562306a36Sopenharmony_ci if (!(walk_state->op_info->flags & AML_NO_OPERAND_RESOLVE) && 39662306a36Sopenharmony_ci (walk_state->op_info->flags & AML_HAS_ARGS)) { 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci /* Resolve all operands */ 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci status = acpi_ex_resolve_operands(walk_state->opcode, 40162306a36Sopenharmony_ci &(walk_state-> 40262306a36Sopenharmony_ci operands 40362306a36Sopenharmony_ci [walk_state-> 40462306a36Sopenharmony_ci num_operands - 1]), 40562306a36Sopenharmony_ci walk_state); 40662306a36Sopenharmony_ci } 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci if (ACPI_SUCCESS(status)) { 40962306a36Sopenharmony_ci /* 41062306a36Sopenharmony_ci * Dispatch the request to the appropriate interpreter handler 41162306a36Sopenharmony_ci * routine. There is one routine per opcode "type" based upon the 41262306a36Sopenharmony_ci * number of opcode arguments and return type. 41362306a36Sopenharmony_ci */ 41462306a36Sopenharmony_ci status = 41562306a36Sopenharmony_ci acpi_gbl_op_type_dispatch[op_type] (walk_state); 41662306a36Sopenharmony_ci } else { 41762306a36Sopenharmony_ci /* 41862306a36Sopenharmony_ci * Treat constructs of the form "Store(LocalX,LocalX)" as noops when the 41962306a36Sopenharmony_ci * Local is uninitialized. 42062306a36Sopenharmony_ci */ 42162306a36Sopenharmony_ci if ((status == AE_AML_UNINITIALIZED_LOCAL) && 42262306a36Sopenharmony_ci (walk_state->opcode == AML_STORE_OP) && 42362306a36Sopenharmony_ci (walk_state->operands[0]->common.type == 42462306a36Sopenharmony_ci ACPI_TYPE_LOCAL_REFERENCE) 42562306a36Sopenharmony_ci && (walk_state->operands[1]->common.type == 42662306a36Sopenharmony_ci ACPI_TYPE_LOCAL_REFERENCE) 42762306a36Sopenharmony_ci && (walk_state->operands[0]->reference.class == 42862306a36Sopenharmony_ci walk_state->operands[1]->reference.class) 42962306a36Sopenharmony_ci && (walk_state->operands[0]->reference.value == 43062306a36Sopenharmony_ci walk_state->operands[1]->reference.value)) { 43162306a36Sopenharmony_ci status = AE_OK; 43262306a36Sopenharmony_ci } else { 43362306a36Sopenharmony_ci ACPI_EXCEPTION((AE_INFO, status, 43462306a36Sopenharmony_ci "While resolving operands for [%s]", 43562306a36Sopenharmony_ci acpi_ps_get_opcode_name 43662306a36Sopenharmony_ci (walk_state->opcode))); 43762306a36Sopenharmony_ci } 43862306a36Sopenharmony_ci } 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci /* Always delete the argument objects and clear the operand stack */ 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci acpi_ds_clear_operands(walk_state); 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_ci /* 44562306a36Sopenharmony_ci * If a result object was returned from above, push it on the 44662306a36Sopenharmony_ci * current result stack 44762306a36Sopenharmony_ci */ 44862306a36Sopenharmony_ci if (ACPI_SUCCESS(status) && walk_state->result_obj) { 44962306a36Sopenharmony_ci status = 45062306a36Sopenharmony_ci acpi_ds_result_push(walk_state->result_obj, 45162306a36Sopenharmony_ci walk_state); 45262306a36Sopenharmony_ci } 45362306a36Sopenharmony_ci break; 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ci default: 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci switch (op_type) { 45862306a36Sopenharmony_ci case AML_TYPE_CONTROL: /* Type 1 opcode, IF/ELSE/WHILE/NOOP */ 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci /* 1 Operand, 0 external_result, 0 internal_result */ 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci status = acpi_ds_exec_end_control_op(walk_state, op); 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ci break; 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci case AML_TYPE_METHOD_CALL: 46762306a36Sopenharmony_ci /* 46862306a36Sopenharmony_ci * If the method is referenced from within a package 46962306a36Sopenharmony_ci * declaration, it is not a invocation of the method, just 47062306a36Sopenharmony_ci * a reference to it. 47162306a36Sopenharmony_ci */ 47262306a36Sopenharmony_ci if ((op->asl.parent) && 47362306a36Sopenharmony_ci ((op->asl.parent->asl.aml_opcode == AML_PACKAGE_OP) 47462306a36Sopenharmony_ci || (op->asl.parent->asl.aml_opcode == 47562306a36Sopenharmony_ci AML_VARIABLE_PACKAGE_OP))) { 47662306a36Sopenharmony_ci ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, 47762306a36Sopenharmony_ci "Method Reference in a Package, Op=%p\n", 47862306a36Sopenharmony_ci op)); 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_ci op->common.node = (struct acpi_namespace_node *) 48162306a36Sopenharmony_ci op->asl.value.arg->asl.node; 48262306a36Sopenharmony_ci acpi_ut_add_reference(op->asl.value.arg->asl. 48362306a36Sopenharmony_ci node->object); 48462306a36Sopenharmony_ci return_ACPI_STATUS(AE_OK); 48562306a36Sopenharmony_ci } 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, 48862306a36Sopenharmony_ci "Method invocation, Op=%p\n", op)); 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci /* 49162306a36Sopenharmony_ci * (AML_METHODCALL) Op->Asl.Value.Arg->Asl.Node contains 49262306a36Sopenharmony_ci * the method Node pointer 49362306a36Sopenharmony_ci */ 49462306a36Sopenharmony_ci /* next_op points to the op that holds the method name */ 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci next_op = first_arg; 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci /* next_op points to first argument op */ 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci next_op = next_op->common.next; 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ci /* 50362306a36Sopenharmony_ci * Get the method's arguments and put them on the operand stack 50462306a36Sopenharmony_ci */ 50562306a36Sopenharmony_ci status = acpi_ds_create_operands(walk_state, next_op); 50662306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 50762306a36Sopenharmony_ci break; 50862306a36Sopenharmony_ci } 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_ci /* 51162306a36Sopenharmony_ci * Since the operands will be passed to another control method, 51262306a36Sopenharmony_ci * we must resolve all local references here (Local variables, 51362306a36Sopenharmony_ci * arguments to *this* method, etc.) 51462306a36Sopenharmony_ci */ 51562306a36Sopenharmony_ci status = acpi_ds_resolve_operands(walk_state); 51662306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_ci /* On error, clear all resolved operands */ 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci acpi_ds_clear_operands(walk_state); 52162306a36Sopenharmony_ci break; 52262306a36Sopenharmony_ci } 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_ci /* 52562306a36Sopenharmony_ci * Tell the walk loop to preempt this running method and 52662306a36Sopenharmony_ci * execute the new method 52762306a36Sopenharmony_ci */ 52862306a36Sopenharmony_ci status = AE_CTRL_TRANSFER; 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_ci /* 53162306a36Sopenharmony_ci * Return now; we don't want to disturb anything, 53262306a36Sopenharmony_ci * especially the operand count! 53362306a36Sopenharmony_ci */ 53462306a36Sopenharmony_ci return_ACPI_STATUS(status); 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci case AML_TYPE_CREATE_FIELD: 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_ci ACPI_DEBUG_PRINT((ACPI_DB_EXEC, 53962306a36Sopenharmony_ci "Executing CreateField Buffer/Index Op=%p\n", 54062306a36Sopenharmony_ci op)); 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ci status = acpi_ds_load2_end_op(walk_state); 54362306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 54462306a36Sopenharmony_ci break; 54562306a36Sopenharmony_ci } 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci status = 54862306a36Sopenharmony_ci acpi_ds_eval_buffer_field_operands(walk_state, op); 54962306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 55062306a36Sopenharmony_ci break; 55162306a36Sopenharmony_ci } 55262306a36Sopenharmony_ci#ifdef ACPI_EXEC_APP 55362306a36Sopenharmony_ci /* 55462306a36Sopenharmony_ci * acpi_exec support for namespace initialization file (initialize 55562306a36Sopenharmony_ci * buffer_fields in this code.) 55662306a36Sopenharmony_ci */ 55762306a36Sopenharmony_ci namepath = 55862306a36Sopenharmony_ci acpi_ns_get_external_pathname(op->common.node); 55962306a36Sopenharmony_ci status = ae_lookup_init_file_entry(namepath, &obj_desc); 56062306a36Sopenharmony_ci if (ACPI_SUCCESS(status)) { 56162306a36Sopenharmony_ci status = 56262306a36Sopenharmony_ci acpi_ex_write_data_to_field(obj_desc, 56362306a36Sopenharmony_ci op->common. 56462306a36Sopenharmony_ci node->object, 56562306a36Sopenharmony_ci NULL); 56662306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 56762306a36Sopenharmony_ci ACPI_EXCEPTION((AE_INFO, status, 56862306a36Sopenharmony_ci "While writing to buffer field")); 56962306a36Sopenharmony_ci } 57062306a36Sopenharmony_ci } 57162306a36Sopenharmony_ci ACPI_FREE(namepath); 57262306a36Sopenharmony_ci status = AE_OK; 57362306a36Sopenharmony_ci#endif 57462306a36Sopenharmony_ci break; 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_ci case AML_TYPE_CREATE_OBJECT: 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_ci ACPI_DEBUG_PRINT((ACPI_DB_EXEC, 57962306a36Sopenharmony_ci "Executing CreateObject (Buffer/Package) Op=%p Child=%p ParentOpcode=%4.4X\n", 58062306a36Sopenharmony_ci op, op->named.value.arg, 58162306a36Sopenharmony_ci op->common.parent->common. 58262306a36Sopenharmony_ci aml_opcode)); 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci switch (op->common.parent->common.aml_opcode) { 58562306a36Sopenharmony_ci case AML_NAME_OP: 58662306a36Sopenharmony_ci /* 58762306a36Sopenharmony_ci * Put the Node on the object stack (Contains the ACPI Name 58862306a36Sopenharmony_ci * of this object) 58962306a36Sopenharmony_ci */ 59062306a36Sopenharmony_ci walk_state->operands[0] = (void *) 59162306a36Sopenharmony_ci op->common.parent->common.node; 59262306a36Sopenharmony_ci walk_state->num_operands = 1; 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_ci status = acpi_ds_create_node(walk_state, 59562306a36Sopenharmony_ci op->common.parent-> 59662306a36Sopenharmony_ci common.node, 59762306a36Sopenharmony_ci op->common.parent); 59862306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 59962306a36Sopenharmony_ci break; 60062306a36Sopenharmony_ci } 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_ci ACPI_FALLTHROUGH; 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_ci case AML_INT_EVAL_SUBTREE_OP: 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_ci status = 60762306a36Sopenharmony_ci acpi_ds_eval_data_object_operands 60862306a36Sopenharmony_ci (walk_state, op, 60962306a36Sopenharmony_ci acpi_ns_get_attached_object(op->common. 61062306a36Sopenharmony_ci parent->common. 61162306a36Sopenharmony_ci node)); 61262306a36Sopenharmony_ci break; 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_ci default: 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_ci status = 61762306a36Sopenharmony_ci acpi_ds_eval_data_object_operands 61862306a36Sopenharmony_ci (walk_state, op, NULL); 61962306a36Sopenharmony_ci break; 62062306a36Sopenharmony_ci } 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci /* 62362306a36Sopenharmony_ci * If a result object was returned from above, push it on the 62462306a36Sopenharmony_ci * current result stack 62562306a36Sopenharmony_ci */ 62662306a36Sopenharmony_ci if (walk_state->result_obj) { 62762306a36Sopenharmony_ci status = 62862306a36Sopenharmony_ci acpi_ds_result_push(walk_state->result_obj, 62962306a36Sopenharmony_ci walk_state); 63062306a36Sopenharmony_ci } 63162306a36Sopenharmony_ci break; 63262306a36Sopenharmony_ci 63362306a36Sopenharmony_ci case AML_TYPE_NAMED_FIELD: 63462306a36Sopenharmony_ci case AML_TYPE_NAMED_COMPLEX: 63562306a36Sopenharmony_ci case AML_TYPE_NAMED_SIMPLE: 63662306a36Sopenharmony_ci case AML_TYPE_NAMED_NO_OBJ: 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_ci status = acpi_ds_load2_end_op(walk_state); 63962306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 64062306a36Sopenharmony_ci break; 64162306a36Sopenharmony_ci } 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_ci if (op->common.aml_opcode == AML_REGION_OP) { 64462306a36Sopenharmony_ci ACPI_DEBUG_PRINT((ACPI_DB_EXEC, 64562306a36Sopenharmony_ci "Executing OpRegion Address/Length Op=%p\n", 64662306a36Sopenharmony_ci op)); 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_ci status = 64962306a36Sopenharmony_ci acpi_ds_eval_region_operands(walk_state, 65062306a36Sopenharmony_ci op); 65162306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 65262306a36Sopenharmony_ci break; 65362306a36Sopenharmony_ci } 65462306a36Sopenharmony_ci } else if (op->common.aml_opcode == AML_DATA_REGION_OP) { 65562306a36Sopenharmony_ci ACPI_DEBUG_PRINT((ACPI_DB_EXEC, 65662306a36Sopenharmony_ci "Executing DataTableRegion Strings Op=%p\n", 65762306a36Sopenharmony_ci op)); 65862306a36Sopenharmony_ci 65962306a36Sopenharmony_ci status = 66062306a36Sopenharmony_ci acpi_ds_eval_table_region_operands 66162306a36Sopenharmony_ci (walk_state, op); 66262306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 66362306a36Sopenharmony_ci break; 66462306a36Sopenharmony_ci } 66562306a36Sopenharmony_ci } else if (op->common.aml_opcode == AML_BANK_FIELD_OP) { 66662306a36Sopenharmony_ci ACPI_DEBUG_PRINT((ACPI_DB_EXEC, 66762306a36Sopenharmony_ci "Executing BankField Op=%p\n", 66862306a36Sopenharmony_ci op)); 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_ci status = 67162306a36Sopenharmony_ci acpi_ds_eval_bank_field_operands(walk_state, 67262306a36Sopenharmony_ci op); 67362306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 67462306a36Sopenharmony_ci break; 67562306a36Sopenharmony_ci } 67662306a36Sopenharmony_ci } 67762306a36Sopenharmony_ci break; 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_ci case AML_TYPE_UNDEFINED: 68062306a36Sopenharmony_ci 68162306a36Sopenharmony_ci ACPI_ERROR((AE_INFO, 68262306a36Sopenharmony_ci "Undefined opcode type Op=%p", op)); 68362306a36Sopenharmony_ci return_ACPI_STATUS(AE_NOT_IMPLEMENTED); 68462306a36Sopenharmony_ci 68562306a36Sopenharmony_ci case AML_TYPE_BOGUS: 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_ci ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, 68862306a36Sopenharmony_ci "Internal opcode=%X type Op=%p\n", 68962306a36Sopenharmony_ci walk_state->opcode, op)); 69062306a36Sopenharmony_ci break; 69162306a36Sopenharmony_ci 69262306a36Sopenharmony_ci default: 69362306a36Sopenharmony_ci 69462306a36Sopenharmony_ci ACPI_ERROR((AE_INFO, 69562306a36Sopenharmony_ci "Unimplemented opcode, class=0x%X " 69662306a36Sopenharmony_ci "type=0x%X Opcode=0x%X Op=%p", 69762306a36Sopenharmony_ci op_class, op_type, op->common.aml_opcode, 69862306a36Sopenharmony_ci op)); 69962306a36Sopenharmony_ci 70062306a36Sopenharmony_ci status = AE_NOT_IMPLEMENTED; 70162306a36Sopenharmony_ci break; 70262306a36Sopenharmony_ci } 70362306a36Sopenharmony_ci } 70462306a36Sopenharmony_ci 70562306a36Sopenharmony_ci /* 70662306a36Sopenharmony_ci * ACPI 2.0 support for 64-bit integers: Truncate numeric 70762306a36Sopenharmony_ci * result value if we are executing from a 32-bit ACPI table 70862306a36Sopenharmony_ci */ 70962306a36Sopenharmony_ci (void)acpi_ex_truncate_for32bit_table(walk_state->result_obj); 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_ci /* 71262306a36Sopenharmony_ci * Check if we just completed the evaluation of a 71362306a36Sopenharmony_ci * conditional predicate 71462306a36Sopenharmony_ci */ 71562306a36Sopenharmony_ci if ((ACPI_SUCCESS(status)) && 71662306a36Sopenharmony_ci (walk_state->control_state) && 71762306a36Sopenharmony_ci (walk_state->control_state->common.state == 71862306a36Sopenharmony_ci ACPI_CONTROL_PREDICATE_EXECUTING) && 71962306a36Sopenharmony_ci (walk_state->control_state->control.predicate_op == op)) { 72062306a36Sopenharmony_ci status = 72162306a36Sopenharmony_ci acpi_ds_get_predicate_value(walk_state, 72262306a36Sopenharmony_ci walk_state->result_obj); 72362306a36Sopenharmony_ci walk_state->result_obj = NULL; 72462306a36Sopenharmony_ci } 72562306a36Sopenharmony_ci 72662306a36Sopenharmony_cicleanup: 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_ci if (walk_state->result_obj) { 72962306a36Sopenharmony_ci 73062306a36Sopenharmony_ci /* Break to debugger to display result */ 73162306a36Sopenharmony_ci 73262306a36Sopenharmony_ci acpi_db_display_result_object(walk_state->result_obj, 73362306a36Sopenharmony_ci walk_state); 73462306a36Sopenharmony_ci 73562306a36Sopenharmony_ci /* 73662306a36Sopenharmony_ci * Delete the result op if and only if: 73762306a36Sopenharmony_ci * Parent will not use the result -- such as any 73862306a36Sopenharmony_ci * non-nested type2 op in a method (parent will be method) 73962306a36Sopenharmony_ci */ 74062306a36Sopenharmony_ci acpi_ds_delete_result_if_not_used(op, walk_state->result_obj, 74162306a36Sopenharmony_ci walk_state); 74262306a36Sopenharmony_ci } 74362306a36Sopenharmony_ci#ifdef _UNDER_DEVELOPMENT 74462306a36Sopenharmony_ci 74562306a36Sopenharmony_ci if (walk_state->parser_state.aml == walk_state->parser_state.aml_end) { 74662306a36Sopenharmony_ci acpi_db_method_end(walk_state); 74762306a36Sopenharmony_ci } 74862306a36Sopenharmony_ci#endif 74962306a36Sopenharmony_ci 75062306a36Sopenharmony_ci /* Invoke exception handler on error */ 75162306a36Sopenharmony_ci 75262306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 75362306a36Sopenharmony_ci status = acpi_ds_method_error(status, walk_state); 75462306a36Sopenharmony_ci } 75562306a36Sopenharmony_ci 75662306a36Sopenharmony_ci /* Always clear the object stack */ 75762306a36Sopenharmony_ci 75862306a36Sopenharmony_ci walk_state->num_operands = 0; 75962306a36Sopenharmony_ci return_ACPI_STATUS(status); 76062306a36Sopenharmony_ci} 761