162306a36Sopenharmony_ci// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 262306a36Sopenharmony_ci/****************************************************************************** 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Module Name: exoparg2 - AML execution - opcodes with 2 arguments 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Copyright (C) 2000 - 2023, Intel Corp. 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci *****************************************************************************/ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <acpi/acpi.h> 1162306a36Sopenharmony_ci#include "accommon.h" 1262306a36Sopenharmony_ci#include "acparser.h" 1362306a36Sopenharmony_ci#include "acinterp.h" 1462306a36Sopenharmony_ci#include "acevents.h" 1562306a36Sopenharmony_ci#include "amlcode.h" 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#define _COMPONENT ACPI_EXECUTER 1862306a36Sopenharmony_ciACPI_MODULE_NAME("exoparg2") 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci/*! 2162306a36Sopenharmony_ci * Naming convention for AML interpreter execution routines. 2262306a36Sopenharmony_ci * 2362306a36Sopenharmony_ci * The routines that begin execution of AML opcodes are named with a common 2462306a36Sopenharmony_ci * convention based upon the number of arguments, the number of target operands, 2562306a36Sopenharmony_ci * and whether or not a value is returned: 2662306a36Sopenharmony_ci * 2762306a36Sopenharmony_ci * AcpiExOpcode_xA_yT_zR 2862306a36Sopenharmony_ci * 2962306a36Sopenharmony_ci * Where: 3062306a36Sopenharmony_ci * 3162306a36Sopenharmony_ci * xA - ARGUMENTS: The number of arguments (input operands) that are 3262306a36Sopenharmony_ci * required for this opcode type (1 through 6 args). 3362306a36Sopenharmony_ci * yT - TARGETS: The number of targets (output operands) that are required 3462306a36Sopenharmony_ci * for this opcode type (0, 1, or 2 targets). 3562306a36Sopenharmony_ci * zR - RETURN VALUE: Indicates whether this opcode type returns a value 3662306a36Sopenharmony_ci * as the function return (0 or 1). 3762306a36Sopenharmony_ci * 3862306a36Sopenharmony_ci * The AcpiExOpcode* functions are called via the Dispatcher component with 3962306a36Sopenharmony_ci * fully resolved operands. 4062306a36Sopenharmony_ci!*/ 4162306a36Sopenharmony_ci/******************************************************************************* 4262306a36Sopenharmony_ci * 4362306a36Sopenharmony_ci * FUNCTION: acpi_ex_opcode_2A_0T_0R 4462306a36Sopenharmony_ci * 4562306a36Sopenharmony_ci * PARAMETERS: walk_state - Current walk state 4662306a36Sopenharmony_ci * 4762306a36Sopenharmony_ci * RETURN: Status 4862306a36Sopenharmony_ci * 4962306a36Sopenharmony_ci * DESCRIPTION: Execute opcode with two arguments, no target, and no return 5062306a36Sopenharmony_ci * value. 5162306a36Sopenharmony_ci * 5262306a36Sopenharmony_ci * ALLOCATION: Deletes both operands 5362306a36Sopenharmony_ci * 5462306a36Sopenharmony_ci ******************************************************************************/ 5562306a36Sopenharmony_ciacpi_status acpi_ex_opcode_2A_0T_0R(struct acpi_walk_state *walk_state) 5662306a36Sopenharmony_ci{ 5762306a36Sopenharmony_ci union acpi_operand_object **operand = &walk_state->operands[0]; 5862306a36Sopenharmony_ci struct acpi_namespace_node *node; 5962306a36Sopenharmony_ci u32 value; 6062306a36Sopenharmony_ci acpi_status status = AE_OK; 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci ACPI_FUNCTION_TRACE_STR(ex_opcode_2A_0T_0R, 6362306a36Sopenharmony_ci acpi_ps_get_opcode_name(walk_state->opcode)); 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci /* Examine the opcode */ 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci switch (walk_state->opcode) { 6862306a36Sopenharmony_ci case AML_NOTIFY_OP: /* Notify (notify_object, notify_value) */ 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci /* The first operand is a namespace node */ 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci node = (struct acpi_namespace_node *)operand[0]; 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci /* Second value is the notify value */ 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci value = (u32) operand[1]->integer.value; 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci /* Are notifies allowed on this object? */ 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci if (!acpi_ev_is_notify_object(node)) { 8162306a36Sopenharmony_ci ACPI_ERROR((AE_INFO, 8262306a36Sopenharmony_ci "Unexpected notify object type [%s]", 8362306a36Sopenharmony_ci acpi_ut_get_type_name(node->type))); 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci status = AE_AML_OPERAND_TYPE; 8662306a36Sopenharmony_ci break; 8762306a36Sopenharmony_ci } 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci /* 9062306a36Sopenharmony_ci * Dispatch the notify to the appropriate handler 9162306a36Sopenharmony_ci * NOTE: the request is queued for execution after this method 9262306a36Sopenharmony_ci * completes. The notify handlers are NOT invoked synchronously 9362306a36Sopenharmony_ci * from this thread -- because handlers may in turn run other 9462306a36Sopenharmony_ci * control methods. 9562306a36Sopenharmony_ci */ 9662306a36Sopenharmony_ci status = acpi_ev_queue_notify_request(node, value); 9762306a36Sopenharmony_ci break; 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci default: 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci ACPI_ERROR((AE_INFO, "Unknown AML opcode 0x%X", 10262306a36Sopenharmony_ci walk_state->opcode)); 10362306a36Sopenharmony_ci status = AE_AML_BAD_OPCODE; 10462306a36Sopenharmony_ci } 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci return_ACPI_STATUS(status); 10762306a36Sopenharmony_ci} 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci/******************************************************************************* 11062306a36Sopenharmony_ci * 11162306a36Sopenharmony_ci * FUNCTION: acpi_ex_opcode_2A_2T_1R 11262306a36Sopenharmony_ci * 11362306a36Sopenharmony_ci * PARAMETERS: walk_state - Current walk state 11462306a36Sopenharmony_ci * 11562306a36Sopenharmony_ci * RETURN: Status 11662306a36Sopenharmony_ci * 11762306a36Sopenharmony_ci * DESCRIPTION: Execute a dyadic operator (2 operands) with 2 output targets 11862306a36Sopenharmony_ci * and one implicit return value. 11962306a36Sopenharmony_ci * 12062306a36Sopenharmony_ci ******************************************************************************/ 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ciacpi_status acpi_ex_opcode_2A_2T_1R(struct acpi_walk_state *walk_state) 12362306a36Sopenharmony_ci{ 12462306a36Sopenharmony_ci union acpi_operand_object **operand = &walk_state->operands[0]; 12562306a36Sopenharmony_ci union acpi_operand_object *return_desc1 = NULL; 12662306a36Sopenharmony_ci union acpi_operand_object *return_desc2 = NULL; 12762306a36Sopenharmony_ci acpi_status status; 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci ACPI_FUNCTION_TRACE_STR(ex_opcode_2A_2T_1R, 13062306a36Sopenharmony_ci acpi_ps_get_opcode_name(walk_state->opcode)); 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci /* Execute the opcode */ 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci switch (walk_state->opcode) { 13562306a36Sopenharmony_ci case AML_DIVIDE_OP: 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci /* Divide (Dividend, Divisor, remainder_result quotient_result) */ 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci return_desc1 = 14062306a36Sopenharmony_ci acpi_ut_create_internal_object(ACPI_TYPE_INTEGER); 14162306a36Sopenharmony_ci if (!return_desc1) { 14262306a36Sopenharmony_ci status = AE_NO_MEMORY; 14362306a36Sopenharmony_ci goto cleanup; 14462306a36Sopenharmony_ci } 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci return_desc2 = 14762306a36Sopenharmony_ci acpi_ut_create_internal_object(ACPI_TYPE_INTEGER); 14862306a36Sopenharmony_ci if (!return_desc2) { 14962306a36Sopenharmony_ci status = AE_NO_MEMORY; 15062306a36Sopenharmony_ci goto cleanup; 15162306a36Sopenharmony_ci } 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci /* Quotient to return_desc1, remainder to return_desc2 */ 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci status = acpi_ut_divide(operand[0]->integer.value, 15662306a36Sopenharmony_ci operand[1]->integer.value, 15762306a36Sopenharmony_ci &return_desc1->integer.value, 15862306a36Sopenharmony_ci &return_desc2->integer.value); 15962306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 16062306a36Sopenharmony_ci goto cleanup; 16162306a36Sopenharmony_ci } 16262306a36Sopenharmony_ci break; 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci default: 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci ACPI_ERROR((AE_INFO, "Unknown AML opcode 0x%X", 16762306a36Sopenharmony_ci walk_state->opcode)); 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci status = AE_AML_BAD_OPCODE; 17062306a36Sopenharmony_ci goto cleanup; 17162306a36Sopenharmony_ci } 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci /* Store the results to the target reference operands */ 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci status = acpi_ex_store(return_desc2, operand[2], walk_state); 17662306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 17762306a36Sopenharmony_ci goto cleanup; 17862306a36Sopenharmony_ci } 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci status = acpi_ex_store(return_desc1, operand[3], walk_state); 18162306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 18262306a36Sopenharmony_ci goto cleanup; 18362306a36Sopenharmony_ci } 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_cicleanup: 18662306a36Sopenharmony_ci /* 18762306a36Sopenharmony_ci * Since the remainder is not returned indirectly, remove a reference to 18862306a36Sopenharmony_ci * it. Only the quotient is returned indirectly. 18962306a36Sopenharmony_ci */ 19062306a36Sopenharmony_ci acpi_ut_remove_reference(return_desc2); 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci /* Delete the return object */ 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci acpi_ut_remove_reference(return_desc1); 19762306a36Sopenharmony_ci } 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci /* Save return object (the remainder) on success */ 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci else { 20262306a36Sopenharmony_ci walk_state->result_obj = return_desc1; 20362306a36Sopenharmony_ci } 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci return_ACPI_STATUS(status); 20662306a36Sopenharmony_ci} 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci/******************************************************************************* 20962306a36Sopenharmony_ci * 21062306a36Sopenharmony_ci * FUNCTION: acpi_ex_opcode_2A_1T_1R 21162306a36Sopenharmony_ci * 21262306a36Sopenharmony_ci * PARAMETERS: walk_state - Current walk state 21362306a36Sopenharmony_ci * 21462306a36Sopenharmony_ci * RETURN: Status 21562306a36Sopenharmony_ci * 21662306a36Sopenharmony_ci * DESCRIPTION: Execute opcode with two arguments, one target, and a return 21762306a36Sopenharmony_ci * value. 21862306a36Sopenharmony_ci * 21962306a36Sopenharmony_ci ******************************************************************************/ 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ciacpi_status acpi_ex_opcode_2A_1T_1R(struct acpi_walk_state *walk_state) 22262306a36Sopenharmony_ci{ 22362306a36Sopenharmony_ci union acpi_operand_object **operand = &walk_state->operands[0]; 22462306a36Sopenharmony_ci union acpi_operand_object *return_desc = NULL; 22562306a36Sopenharmony_ci u64 index; 22662306a36Sopenharmony_ci acpi_status status = AE_OK; 22762306a36Sopenharmony_ci acpi_size length = 0; 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci ACPI_FUNCTION_TRACE_STR(ex_opcode_2A_1T_1R, 23062306a36Sopenharmony_ci acpi_ps_get_opcode_name(walk_state->opcode)); 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci /* Execute the opcode */ 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci if (walk_state->op_info->flags & AML_MATH) { 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci /* All simple math opcodes (add, etc.) */ 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci return_desc = acpi_ut_create_internal_object(ACPI_TYPE_INTEGER); 23962306a36Sopenharmony_ci if (!return_desc) { 24062306a36Sopenharmony_ci status = AE_NO_MEMORY; 24162306a36Sopenharmony_ci goto cleanup; 24262306a36Sopenharmony_ci } 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci return_desc->integer.value = 24562306a36Sopenharmony_ci acpi_ex_do_math_op(walk_state->opcode, 24662306a36Sopenharmony_ci operand[0]->integer.value, 24762306a36Sopenharmony_ci operand[1]->integer.value); 24862306a36Sopenharmony_ci goto store_result_to_target; 24962306a36Sopenharmony_ci } 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci switch (walk_state->opcode) { 25262306a36Sopenharmony_ci case AML_MOD_OP: /* Mod (Dividend, Divisor, remainder_result (ACPI 2.0) */ 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci return_desc = acpi_ut_create_internal_object(ACPI_TYPE_INTEGER); 25562306a36Sopenharmony_ci if (!return_desc) { 25662306a36Sopenharmony_ci status = AE_NO_MEMORY; 25762306a36Sopenharmony_ci goto cleanup; 25862306a36Sopenharmony_ci } 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci /* return_desc will contain the remainder */ 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci status = acpi_ut_divide(operand[0]->integer.value, 26362306a36Sopenharmony_ci operand[1]->integer.value, 26462306a36Sopenharmony_ci NULL, &return_desc->integer.value); 26562306a36Sopenharmony_ci break; 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci case AML_CONCATENATE_OP: /* Concatenate (Data1, Data2, Result) */ 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci status = 27062306a36Sopenharmony_ci acpi_ex_do_concatenate(operand[0], operand[1], &return_desc, 27162306a36Sopenharmony_ci walk_state); 27262306a36Sopenharmony_ci break; 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci case AML_TO_STRING_OP: /* to_string (Buffer, Length, Result) (ACPI 2.0) */ 27562306a36Sopenharmony_ci /* 27662306a36Sopenharmony_ci * Input object is guaranteed to be a buffer at this point (it may have 27762306a36Sopenharmony_ci * been converted.) Copy the raw buffer data to a new object of 27862306a36Sopenharmony_ci * type String. 27962306a36Sopenharmony_ci */ 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci /* 28262306a36Sopenharmony_ci * Get the length of the new string. It is the smallest of: 28362306a36Sopenharmony_ci * 1) Length of the input buffer 28462306a36Sopenharmony_ci * 2) Max length as specified in the to_string operator 28562306a36Sopenharmony_ci * 3) Length of input buffer up to a zero byte (null terminator) 28662306a36Sopenharmony_ci * 28762306a36Sopenharmony_ci * NOTE: A length of zero is ok, and will create a zero-length, null 28862306a36Sopenharmony_ci * terminated string. 28962306a36Sopenharmony_ci */ 29062306a36Sopenharmony_ci while ((length < operand[0]->buffer.length) && /* Length of input buffer */ 29162306a36Sopenharmony_ci (length < operand[1]->integer.value) && /* Length operand */ 29262306a36Sopenharmony_ci (operand[0]->buffer.pointer[length])) { /* Null terminator */ 29362306a36Sopenharmony_ci length++; 29462306a36Sopenharmony_ci } 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci /* Allocate a new string object */ 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci return_desc = acpi_ut_create_string_object(length); 29962306a36Sopenharmony_ci if (!return_desc) { 30062306a36Sopenharmony_ci status = AE_NO_MEMORY; 30162306a36Sopenharmony_ci goto cleanup; 30262306a36Sopenharmony_ci } 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci /* 30562306a36Sopenharmony_ci * Copy the raw buffer data with no transform. 30662306a36Sopenharmony_ci * (NULL terminated already) 30762306a36Sopenharmony_ci */ 30862306a36Sopenharmony_ci memcpy(return_desc->string.pointer, 30962306a36Sopenharmony_ci operand[0]->buffer.pointer, length); 31062306a36Sopenharmony_ci break; 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci case AML_CONCATENATE_TEMPLATE_OP: 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci /* concatenate_res_template (Buffer, Buffer, Result) (ACPI 2.0) */ 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci status = 31762306a36Sopenharmony_ci acpi_ex_concat_template(operand[0], operand[1], 31862306a36Sopenharmony_ci &return_desc, walk_state); 31962306a36Sopenharmony_ci break; 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci case AML_INDEX_OP: /* Index (Source Index Result) */ 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci /* Create the internal return object */ 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci return_desc = 32662306a36Sopenharmony_ci acpi_ut_create_internal_object(ACPI_TYPE_LOCAL_REFERENCE); 32762306a36Sopenharmony_ci if (!return_desc) { 32862306a36Sopenharmony_ci status = AE_NO_MEMORY; 32962306a36Sopenharmony_ci goto cleanup; 33062306a36Sopenharmony_ci } 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci /* Initialize the Index reference object */ 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci index = operand[1]->integer.value; 33562306a36Sopenharmony_ci return_desc->reference.value = (u32) index; 33662306a36Sopenharmony_ci return_desc->reference.class = ACPI_REFCLASS_INDEX; 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci /* 33962306a36Sopenharmony_ci * At this point, the Source operand is a String, Buffer, or Package. 34062306a36Sopenharmony_ci * Verify that the index is within range. 34162306a36Sopenharmony_ci */ 34262306a36Sopenharmony_ci switch ((operand[0])->common.type) { 34362306a36Sopenharmony_ci case ACPI_TYPE_STRING: 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci if (index >= operand[0]->string.length) { 34662306a36Sopenharmony_ci length = operand[0]->string.length; 34762306a36Sopenharmony_ci status = AE_AML_STRING_LIMIT; 34862306a36Sopenharmony_ci } 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci return_desc->reference.target_type = 35162306a36Sopenharmony_ci ACPI_TYPE_BUFFER_FIELD; 35262306a36Sopenharmony_ci return_desc->reference.index_pointer = 35362306a36Sopenharmony_ci &(operand[0]->buffer.pointer[index]); 35462306a36Sopenharmony_ci break; 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci case ACPI_TYPE_BUFFER: 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci if (index >= operand[0]->buffer.length) { 35962306a36Sopenharmony_ci length = operand[0]->buffer.length; 36062306a36Sopenharmony_ci status = AE_AML_BUFFER_LIMIT; 36162306a36Sopenharmony_ci } 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci return_desc->reference.target_type = 36462306a36Sopenharmony_ci ACPI_TYPE_BUFFER_FIELD; 36562306a36Sopenharmony_ci return_desc->reference.index_pointer = 36662306a36Sopenharmony_ci &(operand[0]->buffer.pointer[index]); 36762306a36Sopenharmony_ci break; 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci case ACPI_TYPE_PACKAGE: 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci if (index >= operand[0]->package.count) { 37262306a36Sopenharmony_ci length = operand[0]->package.count; 37362306a36Sopenharmony_ci status = AE_AML_PACKAGE_LIMIT; 37462306a36Sopenharmony_ci } 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci return_desc->reference.target_type = ACPI_TYPE_PACKAGE; 37762306a36Sopenharmony_ci return_desc->reference.where = 37862306a36Sopenharmony_ci &operand[0]->package.elements[index]; 37962306a36Sopenharmony_ci break; 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci default: 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci ACPI_ERROR((AE_INFO, 38462306a36Sopenharmony_ci "Invalid object type: %X", 38562306a36Sopenharmony_ci (operand[0])->common.type)); 38662306a36Sopenharmony_ci status = AE_AML_INTERNAL; 38762306a36Sopenharmony_ci goto cleanup; 38862306a36Sopenharmony_ci } 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci /* Failure means that the Index was beyond the end of the object */ 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 39362306a36Sopenharmony_ci ACPI_BIOS_EXCEPTION((AE_INFO, status, 39462306a36Sopenharmony_ci "Index (0x%X%8.8X) is beyond end of object (length 0x%X)", 39562306a36Sopenharmony_ci ACPI_FORMAT_UINT64(index), 39662306a36Sopenharmony_ci (u32)length)); 39762306a36Sopenharmony_ci goto cleanup; 39862306a36Sopenharmony_ci } 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci /* 40162306a36Sopenharmony_ci * Save the target object and add a reference to it for the life 40262306a36Sopenharmony_ci * of the index 40362306a36Sopenharmony_ci */ 40462306a36Sopenharmony_ci return_desc->reference.object = operand[0]; 40562306a36Sopenharmony_ci acpi_ut_add_reference(operand[0]); 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci /* Store the reference to the Target */ 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci status = acpi_ex_store(return_desc, operand[2], walk_state); 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci /* Return the reference */ 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci walk_state->result_obj = return_desc; 41462306a36Sopenharmony_ci goto cleanup; 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci default: 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci ACPI_ERROR((AE_INFO, "Unknown AML opcode 0x%X", 41962306a36Sopenharmony_ci walk_state->opcode)); 42062306a36Sopenharmony_ci status = AE_AML_BAD_OPCODE; 42162306a36Sopenharmony_ci break; 42262306a36Sopenharmony_ci } 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_cistore_result_to_target: 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci if (ACPI_SUCCESS(status)) { 42762306a36Sopenharmony_ci /* 42862306a36Sopenharmony_ci * Store the result of the operation (which is now in return_desc) into 42962306a36Sopenharmony_ci * the Target descriptor. 43062306a36Sopenharmony_ci */ 43162306a36Sopenharmony_ci status = acpi_ex_store(return_desc, operand[2], walk_state); 43262306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 43362306a36Sopenharmony_ci goto cleanup; 43462306a36Sopenharmony_ci } 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci if (!walk_state->result_obj) { 43762306a36Sopenharmony_ci walk_state->result_obj = return_desc; 43862306a36Sopenharmony_ci } 43962306a36Sopenharmony_ci } 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_cicleanup: 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci /* Delete return object on error */ 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 44662306a36Sopenharmony_ci acpi_ut_remove_reference(return_desc); 44762306a36Sopenharmony_ci walk_state->result_obj = NULL; 44862306a36Sopenharmony_ci } 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci return_ACPI_STATUS(status); 45162306a36Sopenharmony_ci} 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci/******************************************************************************* 45462306a36Sopenharmony_ci * 45562306a36Sopenharmony_ci * FUNCTION: acpi_ex_opcode_2A_0T_1R 45662306a36Sopenharmony_ci * 45762306a36Sopenharmony_ci * PARAMETERS: walk_state - Current walk state 45862306a36Sopenharmony_ci * 45962306a36Sopenharmony_ci * RETURN: Status 46062306a36Sopenharmony_ci * 46162306a36Sopenharmony_ci * DESCRIPTION: Execute opcode with 2 arguments, no target, and a return value 46262306a36Sopenharmony_ci * 46362306a36Sopenharmony_ci ******************************************************************************/ 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ciacpi_status acpi_ex_opcode_2A_0T_1R(struct acpi_walk_state *walk_state) 46662306a36Sopenharmony_ci{ 46762306a36Sopenharmony_ci union acpi_operand_object **operand = &walk_state->operands[0]; 46862306a36Sopenharmony_ci union acpi_operand_object *return_desc = NULL; 46962306a36Sopenharmony_ci acpi_status status = AE_OK; 47062306a36Sopenharmony_ci u8 logical_result = FALSE; 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_ci ACPI_FUNCTION_TRACE_STR(ex_opcode_2A_0T_1R, 47362306a36Sopenharmony_ci acpi_ps_get_opcode_name(walk_state->opcode)); 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci /* Create the internal return object */ 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci return_desc = acpi_ut_create_internal_object(ACPI_TYPE_INTEGER); 47862306a36Sopenharmony_ci if (!return_desc) { 47962306a36Sopenharmony_ci status = AE_NO_MEMORY; 48062306a36Sopenharmony_ci goto cleanup; 48162306a36Sopenharmony_ci } 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci /* Execute the Opcode */ 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci if (walk_state->op_info->flags & AML_LOGICAL_NUMERIC) { 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci /* logical_op (Operand0, Operand1) */ 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci status = acpi_ex_do_logical_numeric_op(walk_state->opcode, 49062306a36Sopenharmony_ci operand[0]->integer. 49162306a36Sopenharmony_ci value, 49262306a36Sopenharmony_ci operand[1]->integer. 49362306a36Sopenharmony_ci value, &logical_result); 49462306a36Sopenharmony_ci goto store_logical_result; 49562306a36Sopenharmony_ci } else if (walk_state->op_info->flags & AML_LOGICAL) { 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci /* logical_op (Operand0, Operand1) */ 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_ci status = acpi_ex_do_logical_op(walk_state->opcode, operand[0], 50062306a36Sopenharmony_ci operand[1], &logical_result); 50162306a36Sopenharmony_ci goto store_logical_result; 50262306a36Sopenharmony_ci } 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ci switch (walk_state->opcode) { 50562306a36Sopenharmony_ci case AML_ACQUIRE_OP: /* Acquire (mutex_object, Timeout) */ 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci status = 50862306a36Sopenharmony_ci acpi_ex_acquire_mutex(operand[1], operand[0], walk_state); 50962306a36Sopenharmony_ci if (status == AE_TIME) { 51062306a36Sopenharmony_ci logical_result = TRUE; /* TRUE = Acquire timed out */ 51162306a36Sopenharmony_ci status = AE_OK; 51262306a36Sopenharmony_ci } 51362306a36Sopenharmony_ci break; 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci case AML_WAIT_OP: /* Wait (event_object, Timeout) */ 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_ci status = acpi_ex_system_wait_event(operand[1], operand[0]); 51862306a36Sopenharmony_ci if (status == AE_TIME) { 51962306a36Sopenharmony_ci logical_result = TRUE; /* TRUE, Wait timed out */ 52062306a36Sopenharmony_ci status = AE_OK; 52162306a36Sopenharmony_ci } 52262306a36Sopenharmony_ci break; 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_ci default: 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_ci ACPI_ERROR((AE_INFO, "Unknown AML opcode 0x%X", 52762306a36Sopenharmony_ci walk_state->opcode)); 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ci status = AE_AML_BAD_OPCODE; 53062306a36Sopenharmony_ci goto cleanup; 53162306a36Sopenharmony_ci } 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_cistore_logical_result: 53462306a36Sopenharmony_ci /* 53562306a36Sopenharmony_ci * Set return value to according to logical_result. logical TRUE (all ones) 53662306a36Sopenharmony_ci * Default is FALSE (zero) 53762306a36Sopenharmony_ci */ 53862306a36Sopenharmony_ci if (logical_result) { 53962306a36Sopenharmony_ci return_desc->integer.value = ACPI_UINT64_MAX; 54062306a36Sopenharmony_ci } 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_cicleanup: 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_ci /* Delete return object on error */ 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 54762306a36Sopenharmony_ci acpi_ut_remove_reference(return_desc); 54862306a36Sopenharmony_ci } 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_ci /* Save return object on success */ 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ci else { 55362306a36Sopenharmony_ci walk_state->result_obj = return_desc; 55462306a36Sopenharmony_ci } 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci return_ACPI_STATUS(status); 55762306a36Sopenharmony_ci} 558