162306a36Sopenharmony_ci// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 262306a36Sopenharmony_ci/****************************************************************************** 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Module Name: exoparg6 - AML execution - opcodes with 6 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 "acinterp.h" 1362306a36Sopenharmony_ci#include "acparser.h" 1462306a36Sopenharmony_ci#include "amlcode.h" 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci#define _COMPONENT ACPI_EXECUTER 1762306a36Sopenharmony_ciACPI_MODULE_NAME("exoparg6") 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci/*! 2062306a36Sopenharmony_ci * Naming convention for AML interpreter execution routines. 2162306a36Sopenharmony_ci * 2262306a36Sopenharmony_ci * The routines that begin execution of AML opcodes are named with a common 2362306a36Sopenharmony_ci * convention based upon the number of arguments, the number of target operands, 2462306a36Sopenharmony_ci * and whether or not a value is returned: 2562306a36Sopenharmony_ci * 2662306a36Sopenharmony_ci * AcpiExOpcode_xA_yT_zR 2762306a36Sopenharmony_ci * 2862306a36Sopenharmony_ci * Where: 2962306a36Sopenharmony_ci * 3062306a36Sopenharmony_ci * xA - ARGUMENTS: The number of arguments (input operands) that are 3162306a36Sopenharmony_ci * required for this opcode type (1 through 6 args). 3262306a36Sopenharmony_ci * yT - TARGETS: The number of targets (output operands) that are required 3362306a36Sopenharmony_ci * for this opcode type (0, 1, or 2 targets). 3462306a36Sopenharmony_ci * zR - RETURN VALUE: Indicates whether this opcode type returns a value 3562306a36Sopenharmony_ci * as the function return (0 or 1). 3662306a36Sopenharmony_ci * 3762306a36Sopenharmony_ci * The AcpiExOpcode* functions are called via the Dispatcher component with 3862306a36Sopenharmony_ci * fully resolved operands. 3962306a36Sopenharmony_ci!*/ 4062306a36Sopenharmony_ci/* Local prototypes */ 4162306a36Sopenharmony_cistatic u8 4262306a36Sopenharmony_ciacpi_ex_do_match(u32 match_op, 4362306a36Sopenharmony_ci union acpi_operand_object *package_obj, 4462306a36Sopenharmony_ci union acpi_operand_object *match_obj); 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci/******************************************************************************* 4762306a36Sopenharmony_ci * 4862306a36Sopenharmony_ci * FUNCTION: acpi_ex_do_match 4962306a36Sopenharmony_ci * 5062306a36Sopenharmony_ci * PARAMETERS: match_op - The AML match operand 5162306a36Sopenharmony_ci * package_obj - Object from the target package 5262306a36Sopenharmony_ci * match_obj - Object to be matched 5362306a36Sopenharmony_ci * 5462306a36Sopenharmony_ci * RETURN: TRUE if the match is successful, FALSE otherwise 5562306a36Sopenharmony_ci * 5662306a36Sopenharmony_ci * DESCRIPTION: Implements the low-level match for the ASL Match operator. 5762306a36Sopenharmony_ci * Package elements will be implicitly converted to the type of 5862306a36Sopenharmony_ci * the match object (Integer/Buffer/String). 5962306a36Sopenharmony_ci * 6062306a36Sopenharmony_ci ******************************************************************************/ 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_cistatic u8 6362306a36Sopenharmony_ciacpi_ex_do_match(u32 match_op, 6462306a36Sopenharmony_ci union acpi_operand_object *package_obj, 6562306a36Sopenharmony_ci union acpi_operand_object *match_obj) 6662306a36Sopenharmony_ci{ 6762306a36Sopenharmony_ci u8 logical_result = TRUE; 6862306a36Sopenharmony_ci acpi_status status; 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci /* 7162306a36Sopenharmony_ci * Note: Since the package_obj/match_obj ordering is opposite to that of 7262306a36Sopenharmony_ci * the standard logical operators, we have to reverse them when we call 7362306a36Sopenharmony_ci * do_logical_op in order to make the implicit conversion rules work 7462306a36Sopenharmony_ci * correctly. However, this means we have to flip the entire equation 7562306a36Sopenharmony_ci * also. A bit ugly perhaps, but overall, better than fussing the 7662306a36Sopenharmony_ci * parameters around at runtime, over and over again. 7762306a36Sopenharmony_ci * 7862306a36Sopenharmony_ci * Below, P[i] refers to the package element, M refers to the Match object. 7962306a36Sopenharmony_ci */ 8062306a36Sopenharmony_ci switch (match_op) { 8162306a36Sopenharmony_ci case MATCH_MTR: 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci /* Always true */ 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci break; 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci case MATCH_MEQ: 8862306a36Sopenharmony_ci /* 8962306a36Sopenharmony_ci * True if equal: (P[i] == M) 9062306a36Sopenharmony_ci * Change to: (M == P[i]) 9162306a36Sopenharmony_ci */ 9262306a36Sopenharmony_ci status = 9362306a36Sopenharmony_ci acpi_ex_do_logical_op(AML_LOGICAL_EQUAL_OP, match_obj, 9462306a36Sopenharmony_ci package_obj, &logical_result); 9562306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 9662306a36Sopenharmony_ci return (FALSE); 9762306a36Sopenharmony_ci } 9862306a36Sopenharmony_ci break; 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci case MATCH_MLE: 10162306a36Sopenharmony_ci /* 10262306a36Sopenharmony_ci * True if less than or equal: (P[i] <= M) (P[i] not_greater than M) 10362306a36Sopenharmony_ci * Change to: (M >= P[i]) (M not_less than P[i]) 10462306a36Sopenharmony_ci */ 10562306a36Sopenharmony_ci status = 10662306a36Sopenharmony_ci acpi_ex_do_logical_op(AML_LOGICAL_LESS_OP, match_obj, 10762306a36Sopenharmony_ci package_obj, &logical_result); 10862306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 10962306a36Sopenharmony_ci return (FALSE); 11062306a36Sopenharmony_ci } 11162306a36Sopenharmony_ci logical_result = (u8) ! logical_result; 11262306a36Sopenharmony_ci break; 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci case MATCH_MLT: 11562306a36Sopenharmony_ci /* 11662306a36Sopenharmony_ci * True if less than: (P[i] < M) 11762306a36Sopenharmony_ci * Change to: (M > P[i]) 11862306a36Sopenharmony_ci */ 11962306a36Sopenharmony_ci status = 12062306a36Sopenharmony_ci acpi_ex_do_logical_op(AML_LOGICAL_GREATER_OP, match_obj, 12162306a36Sopenharmony_ci package_obj, &logical_result); 12262306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 12362306a36Sopenharmony_ci return (FALSE); 12462306a36Sopenharmony_ci } 12562306a36Sopenharmony_ci break; 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci case MATCH_MGE: 12862306a36Sopenharmony_ci /* 12962306a36Sopenharmony_ci * True if greater than or equal: (P[i] >= M) (P[i] not_less than M) 13062306a36Sopenharmony_ci * Change to: (M <= P[i]) (M not_greater than P[i]) 13162306a36Sopenharmony_ci */ 13262306a36Sopenharmony_ci status = 13362306a36Sopenharmony_ci acpi_ex_do_logical_op(AML_LOGICAL_GREATER_OP, match_obj, 13462306a36Sopenharmony_ci package_obj, &logical_result); 13562306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 13662306a36Sopenharmony_ci return (FALSE); 13762306a36Sopenharmony_ci } 13862306a36Sopenharmony_ci logical_result = (u8) ! logical_result; 13962306a36Sopenharmony_ci break; 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci case MATCH_MGT: 14262306a36Sopenharmony_ci /* 14362306a36Sopenharmony_ci * True if greater than: (P[i] > M) 14462306a36Sopenharmony_ci * Change to: (M < P[i]) 14562306a36Sopenharmony_ci */ 14662306a36Sopenharmony_ci status = 14762306a36Sopenharmony_ci acpi_ex_do_logical_op(AML_LOGICAL_LESS_OP, match_obj, 14862306a36Sopenharmony_ci package_obj, &logical_result); 14962306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 15062306a36Sopenharmony_ci return (FALSE); 15162306a36Sopenharmony_ci } 15262306a36Sopenharmony_ci break; 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci default: 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci /* Undefined */ 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci return (FALSE); 15962306a36Sopenharmony_ci } 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci return (logical_result); 16262306a36Sopenharmony_ci} 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci/******************************************************************************* 16562306a36Sopenharmony_ci * 16662306a36Sopenharmony_ci * FUNCTION: acpi_ex_opcode_6A_0T_1R 16762306a36Sopenharmony_ci * 16862306a36Sopenharmony_ci * PARAMETERS: walk_state - Current walk state 16962306a36Sopenharmony_ci * 17062306a36Sopenharmony_ci * RETURN: Status 17162306a36Sopenharmony_ci * 17262306a36Sopenharmony_ci * DESCRIPTION: Execute opcode with 6 arguments, no target, and a return value 17362306a36Sopenharmony_ci * 17462306a36Sopenharmony_ci ******************************************************************************/ 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ciacpi_status acpi_ex_opcode_6A_0T_1R(struct acpi_walk_state *walk_state) 17762306a36Sopenharmony_ci{ 17862306a36Sopenharmony_ci union acpi_operand_object **operand = &walk_state->operands[0]; 17962306a36Sopenharmony_ci union acpi_operand_object *return_desc = NULL; 18062306a36Sopenharmony_ci acpi_status status = AE_OK; 18162306a36Sopenharmony_ci u64 index; 18262306a36Sopenharmony_ci union acpi_operand_object *this_element; 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci ACPI_FUNCTION_TRACE_STR(ex_opcode_6A_0T_1R, 18562306a36Sopenharmony_ci acpi_ps_get_opcode_name(walk_state->opcode)); 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci switch (walk_state->opcode) { 18862306a36Sopenharmony_ci case AML_MATCH_OP: 18962306a36Sopenharmony_ci /* 19062306a36Sopenharmony_ci * Match (search_pkg[0], match_op1[1], match_obj1[2], 19162306a36Sopenharmony_ci * match_op2[3], match_obj2[4], start_index[5]) 19262306a36Sopenharmony_ci */ 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci /* Validate both Match Term Operators (MTR, MEQ, etc.) */ 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci if ((operand[1]->integer.value > MAX_MATCH_OPERATOR) || 19762306a36Sopenharmony_ci (operand[3]->integer.value > MAX_MATCH_OPERATOR)) { 19862306a36Sopenharmony_ci ACPI_ERROR((AE_INFO, "Match operator out of range")); 19962306a36Sopenharmony_ci status = AE_AML_OPERAND_VALUE; 20062306a36Sopenharmony_ci goto cleanup; 20162306a36Sopenharmony_ci } 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci /* Get the package start_index, validate against the package length */ 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci index = operand[5]->integer.value; 20662306a36Sopenharmony_ci if (index >= operand[0]->package.count) { 20762306a36Sopenharmony_ci ACPI_ERROR((AE_INFO, 20862306a36Sopenharmony_ci "Index (0x%8.8X%8.8X) beyond package end (0x%X)", 20962306a36Sopenharmony_ci ACPI_FORMAT_UINT64(index), 21062306a36Sopenharmony_ci operand[0]->package.count)); 21162306a36Sopenharmony_ci status = AE_AML_PACKAGE_LIMIT; 21262306a36Sopenharmony_ci goto cleanup; 21362306a36Sopenharmony_ci } 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci /* Create an integer for the return value */ 21662306a36Sopenharmony_ci /* Default return value is ACPI_UINT64_MAX if no match found */ 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci return_desc = acpi_ut_create_integer_object(ACPI_UINT64_MAX); 21962306a36Sopenharmony_ci if (!return_desc) { 22062306a36Sopenharmony_ci status = AE_NO_MEMORY; 22162306a36Sopenharmony_ci goto cleanup; 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci } 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci /* 22662306a36Sopenharmony_ci * Examine each element until a match is found. Both match conditions 22762306a36Sopenharmony_ci * must be satisfied for a match to occur. Within the loop, 22862306a36Sopenharmony_ci * "continue" signifies that the current element does not match 22962306a36Sopenharmony_ci * and the next should be examined. 23062306a36Sopenharmony_ci * 23162306a36Sopenharmony_ci * Upon finding a match, the loop will terminate via "break" at 23262306a36Sopenharmony_ci * the bottom. If it terminates "normally", match_value will be 23362306a36Sopenharmony_ci * ACPI_UINT64_MAX (Ones) (its initial value) indicating that no 23462306a36Sopenharmony_ci * match was found. 23562306a36Sopenharmony_ci */ 23662306a36Sopenharmony_ci for (; index < operand[0]->package.count; index++) { 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci /* Get the current package element */ 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci this_element = operand[0]->package.elements[index]; 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci /* Treat any uninitialized (NULL) elements as non-matching */ 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci if (!this_element) { 24562306a36Sopenharmony_ci continue; 24662306a36Sopenharmony_ci } 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci /* 24962306a36Sopenharmony_ci * Both match conditions must be satisfied. Execution of a continue 25062306a36Sopenharmony_ci * (proceed to next iteration of enclosing for loop) signifies a 25162306a36Sopenharmony_ci * non-match. 25262306a36Sopenharmony_ci */ 25362306a36Sopenharmony_ci if (!acpi_ex_do_match((u32) operand[1]->integer.value, 25462306a36Sopenharmony_ci this_element, operand[2])) { 25562306a36Sopenharmony_ci continue; 25662306a36Sopenharmony_ci } 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci if (!acpi_ex_do_match((u32) operand[3]->integer.value, 25962306a36Sopenharmony_ci this_element, operand[4])) { 26062306a36Sopenharmony_ci continue; 26162306a36Sopenharmony_ci } 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci /* Match found: Index is the return value */ 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci return_desc->integer.value = index; 26662306a36Sopenharmony_ci break; 26762306a36Sopenharmony_ci } 26862306a36Sopenharmony_ci break; 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci case AML_LOAD_TABLE_OP: 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci status = acpi_ex_load_table_op(walk_state, &return_desc); 27362306a36Sopenharmony_ci break; 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci default: 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci ACPI_ERROR((AE_INFO, "Unknown AML opcode 0x%X", 27862306a36Sopenharmony_ci walk_state->opcode)); 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci status = AE_AML_BAD_OPCODE; 28162306a36Sopenharmony_ci goto cleanup; 28262306a36Sopenharmony_ci } 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_cicleanup: 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci /* Delete return object on error */ 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 28962306a36Sopenharmony_ci acpi_ut_remove_reference(return_desc); 29062306a36Sopenharmony_ci } 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci /* Save return object on success */ 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci else { 29562306a36Sopenharmony_ci walk_state->result_obj = return_desc; 29662306a36Sopenharmony_ci } 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci return_ACPI_STATUS(status); 29962306a36Sopenharmony_ci} 300