162306a36Sopenharmony_ci// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 262306a36Sopenharmony_ci/******************************************************************************* 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Module Name: nseval - Object evaluation, includes control method execution 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 "acinterp.h" 1262306a36Sopenharmony_ci#include "acnamesp.h" 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#define _COMPONENT ACPI_NAMESPACE 1562306a36Sopenharmony_ciACPI_MODULE_NAME("nseval") 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci/******************************************************************************* 1862306a36Sopenharmony_ci * 1962306a36Sopenharmony_ci * FUNCTION: acpi_ns_evaluate 2062306a36Sopenharmony_ci * 2162306a36Sopenharmony_ci * PARAMETERS: info - Evaluation info block, contains these fields 2262306a36Sopenharmony_ci * and more: 2362306a36Sopenharmony_ci * prefix_node - Prefix or Method/Object Node to execute 2462306a36Sopenharmony_ci * relative_path - Name of method to execute, If NULL, the 2562306a36Sopenharmony_ci * Node is the object to execute 2662306a36Sopenharmony_ci * parameters - List of parameters to pass to the method, 2762306a36Sopenharmony_ci * terminated by NULL. Params itself may be 2862306a36Sopenharmony_ci * NULL if no parameters are being passed. 2962306a36Sopenharmony_ci * parameter_type - Type of Parameter list 3062306a36Sopenharmony_ci * return_object - Where to put method's return value (if 3162306a36Sopenharmony_ci * any). If NULL, no value is returned. 3262306a36Sopenharmony_ci * flags - ACPI_IGNORE_RETURN_VALUE to delete return 3362306a36Sopenharmony_ci * 3462306a36Sopenharmony_ci * RETURN: Status 3562306a36Sopenharmony_ci * 3662306a36Sopenharmony_ci * DESCRIPTION: Execute a control method or return the current value of an 3762306a36Sopenharmony_ci * ACPI namespace object. 3862306a36Sopenharmony_ci * 3962306a36Sopenharmony_ci * MUTEX: Locks interpreter 4062306a36Sopenharmony_ci * 4162306a36Sopenharmony_ci ******************************************************************************/ 4262306a36Sopenharmony_ciacpi_status acpi_ns_evaluate(struct acpi_evaluate_info *info) 4362306a36Sopenharmony_ci{ 4462306a36Sopenharmony_ci acpi_status status; 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci ACPI_FUNCTION_TRACE(ns_evaluate); 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci if (!info) { 4962306a36Sopenharmony_ci return_ACPI_STATUS(AE_BAD_PARAMETER); 5062306a36Sopenharmony_ci } 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci if (!info->node) { 5362306a36Sopenharmony_ci /* 5462306a36Sopenharmony_ci * Get the actual namespace node for the target object if we 5562306a36Sopenharmony_ci * need to. Handles these cases: 5662306a36Sopenharmony_ci * 5762306a36Sopenharmony_ci * 1) Null node, valid pathname from root (absolute path) 5862306a36Sopenharmony_ci * 2) Node and valid pathname (path relative to Node) 5962306a36Sopenharmony_ci * 3) Node, Null pathname 6062306a36Sopenharmony_ci */ 6162306a36Sopenharmony_ci status = 6262306a36Sopenharmony_ci acpi_ns_get_node(info->prefix_node, info->relative_pathname, 6362306a36Sopenharmony_ci ACPI_NS_NO_UPSEARCH, &info->node); 6462306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 6562306a36Sopenharmony_ci return_ACPI_STATUS(status); 6662306a36Sopenharmony_ci } 6762306a36Sopenharmony_ci } 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci /* 7062306a36Sopenharmony_ci * For a method alias, we must grab the actual method node so that 7162306a36Sopenharmony_ci * proper scoping context will be established before execution. 7262306a36Sopenharmony_ci */ 7362306a36Sopenharmony_ci if (acpi_ns_get_type(info->node) == ACPI_TYPE_LOCAL_METHOD_ALIAS) { 7462306a36Sopenharmony_ci info->node = 7562306a36Sopenharmony_ci ACPI_CAST_PTR(struct acpi_namespace_node, 7662306a36Sopenharmony_ci info->node->object); 7762306a36Sopenharmony_ci } 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci /* Complete the info block initialization */ 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci info->return_object = NULL; 8262306a36Sopenharmony_ci info->node_flags = info->node->flags; 8362306a36Sopenharmony_ci info->obj_desc = acpi_ns_get_attached_object(info->node); 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci ACPI_DEBUG_PRINT((ACPI_DB_NAMES, "%s [%p] Value %p\n", 8662306a36Sopenharmony_ci info->relative_pathname, info->node, 8762306a36Sopenharmony_ci acpi_ns_get_attached_object(info->node))); 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci /* Get info if we have a predefined name (_HID, etc.) */ 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci info->predefined = 9262306a36Sopenharmony_ci acpi_ut_match_predefined_method(info->node->name.ascii); 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci /* Get the full pathname to the object, for use in warning messages */ 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci info->full_pathname = acpi_ns_get_normalized_pathname(info->node, TRUE); 9762306a36Sopenharmony_ci if (!info->full_pathname) { 9862306a36Sopenharmony_ci return_ACPI_STATUS(AE_NO_MEMORY); 9962306a36Sopenharmony_ci } 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci /* Optional object evaluation log */ 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci ACPI_DEBUG_PRINT_RAW((ACPI_DB_EVALUATION, 10462306a36Sopenharmony_ci "%-26s: %s (%s)\n", " Enter evaluation", 10562306a36Sopenharmony_ci &info->full_pathname[1], 10662306a36Sopenharmony_ci acpi_ut_get_type_name(info->node->type))); 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci /* Count the number of arguments being passed in */ 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci info->param_count = 0; 11162306a36Sopenharmony_ci if (info->parameters) { 11262306a36Sopenharmony_ci while (info->parameters[info->param_count]) { 11362306a36Sopenharmony_ci info->param_count++; 11462306a36Sopenharmony_ci } 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci /* Warn on impossible argument count */ 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci if (info->param_count > ACPI_METHOD_NUM_ARGS) { 11962306a36Sopenharmony_ci ACPI_WARN_PREDEFINED((AE_INFO, info->full_pathname, 12062306a36Sopenharmony_ci ACPI_WARN_ALWAYS, 12162306a36Sopenharmony_ci "Excess arguments (%u) - using only %u", 12262306a36Sopenharmony_ci info->param_count, 12362306a36Sopenharmony_ci ACPI_METHOD_NUM_ARGS)); 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci info->param_count = ACPI_METHOD_NUM_ARGS; 12662306a36Sopenharmony_ci } 12762306a36Sopenharmony_ci } 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci /* 13062306a36Sopenharmony_ci * For predefined names: Check that the declared argument count 13162306a36Sopenharmony_ci * matches the ACPI spec -- otherwise this is a BIOS error. 13262306a36Sopenharmony_ci */ 13362306a36Sopenharmony_ci acpi_ns_check_acpi_compliance(info->full_pathname, info->node, 13462306a36Sopenharmony_ci info->predefined); 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci /* 13762306a36Sopenharmony_ci * For all names: Check that the incoming argument count for 13862306a36Sopenharmony_ci * this method/object matches the actual ASL/AML definition. 13962306a36Sopenharmony_ci */ 14062306a36Sopenharmony_ci acpi_ns_check_argument_count(info->full_pathname, info->node, 14162306a36Sopenharmony_ci info->param_count, info->predefined); 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci /* For predefined names: Typecheck all incoming arguments */ 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci acpi_ns_check_argument_types(info); 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci /* 14862306a36Sopenharmony_ci * Three major evaluation cases: 14962306a36Sopenharmony_ci * 15062306a36Sopenharmony_ci * 1) Object types that cannot be evaluated by definition 15162306a36Sopenharmony_ci * 2) The object is a control method -- execute it 15262306a36Sopenharmony_ci * 3) The object is not a method -- just return it's current value 15362306a36Sopenharmony_ci */ 15462306a36Sopenharmony_ci switch (acpi_ns_get_type(info->node)) { 15562306a36Sopenharmony_ci case ACPI_TYPE_ANY: 15662306a36Sopenharmony_ci case ACPI_TYPE_DEVICE: 15762306a36Sopenharmony_ci case ACPI_TYPE_EVENT: 15862306a36Sopenharmony_ci case ACPI_TYPE_MUTEX: 15962306a36Sopenharmony_ci case ACPI_TYPE_REGION: 16062306a36Sopenharmony_ci case ACPI_TYPE_THERMAL: 16162306a36Sopenharmony_ci case ACPI_TYPE_LOCAL_SCOPE: 16262306a36Sopenharmony_ci /* 16362306a36Sopenharmony_ci * 1) Disallow evaluation of these object types. For these, 16462306a36Sopenharmony_ci * object evaluation is undefined. 16562306a36Sopenharmony_ci */ 16662306a36Sopenharmony_ci ACPI_ERROR((AE_INFO, 16762306a36Sopenharmony_ci "%s: This object type [%s] " 16862306a36Sopenharmony_ci "never contains data and cannot be evaluated", 16962306a36Sopenharmony_ci info->full_pathname, 17062306a36Sopenharmony_ci acpi_ut_get_type_name(info->node->type))); 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci status = AE_TYPE; 17362306a36Sopenharmony_ci goto cleanup; 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci case ACPI_TYPE_METHOD: 17662306a36Sopenharmony_ci /* 17762306a36Sopenharmony_ci * 2) Object is a control method - execute it 17862306a36Sopenharmony_ci */ 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci /* Verify that there is a method object associated with this node */ 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci if (!info->obj_desc) { 18362306a36Sopenharmony_ci ACPI_ERROR((AE_INFO, 18462306a36Sopenharmony_ci "%s: Method has no attached sub-object", 18562306a36Sopenharmony_ci info->full_pathname)); 18662306a36Sopenharmony_ci status = AE_NULL_OBJECT; 18762306a36Sopenharmony_ci goto cleanup; 18862306a36Sopenharmony_ci } 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci ACPI_DEBUG_PRINT((ACPI_DB_EXEC, 19162306a36Sopenharmony_ci "**** Execute method [%s] at AML address %p length %X\n", 19262306a36Sopenharmony_ci info->full_pathname, 19362306a36Sopenharmony_ci info->obj_desc->method.aml_start + 1, 19462306a36Sopenharmony_ci info->obj_desc->method.aml_length - 1)); 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci /* 19762306a36Sopenharmony_ci * Any namespace deletion must acquire both the namespace and 19862306a36Sopenharmony_ci * interpreter locks to ensure that no thread is using the portion of 19962306a36Sopenharmony_ci * the namespace that is being deleted. 20062306a36Sopenharmony_ci * 20162306a36Sopenharmony_ci * Execute the method via the interpreter. The interpreter is locked 20262306a36Sopenharmony_ci * here before calling into the AML parser 20362306a36Sopenharmony_ci */ 20462306a36Sopenharmony_ci acpi_ex_enter_interpreter(); 20562306a36Sopenharmony_ci status = acpi_ps_execute_method(info); 20662306a36Sopenharmony_ci acpi_ex_exit_interpreter(); 20762306a36Sopenharmony_ci break; 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci default: 21062306a36Sopenharmony_ci /* 21162306a36Sopenharmony_ci * 3) All other non-method objects -- get the current object value 21262306a36Sopenharmony_ci */ 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci /* 21562306a36Sopenharmony_ci * Some objects require additional resolution steps (e.g., the Node 21662306a36Sopenharmony_ci * may be a field that must be read, etc.) -- we can't just grab 21762306a36Sopenharmony_ci * the object out of the node. 21862306a36Sopenharmony_ci * 21962306a36Sopenharmony_ci * Use resolve_node_to_value() to get the associated value. 22062306a36Sopenharmony_ci * 22162306a36Sopenharmony_ci * NOTE: we can get away with passing in NULL for a walk state because 22262306a36Sopenharmony_ci * the Node is guaranteed to not be a reference to either a method 22362306a36Sopenharmony_ci * local or a method argument (because this interface is never called 22462306a36Sopenharmony_ci * from a running method.) 22562306a36Sopenharmony_ci * 22662306a36Sopenharmony_ci * Even though we do not directly invoke the interpreter for object 22762306a36Sopenharmony_ci * resolution, we must lock it because we could access an op_region. 22862306a36Sopenharmony_ci * The op_region access code assumes that the interpreter is locked. 22962306a36Sopenharmony_ci */ 23062306a36Sopenharmony_ci acpi_ex_enter_interpreter(); 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci /* TBD: resolve_node_to_value has a strange interface, fix */ 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci info->return_object = 23562306a36Sopenharmony_ci ACPI_CAST_PTR(union acpi_operand_object, info->node); 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci status = 23862306a36Sopenharmony_ci acpi_ex_resolve_node_to_value(ACPI_CAST_INDIRECT_PTR 23962306a36Sopenharmony_ci (struct acpi_namespace_node, 24062306a36Sopenharmony_ci &info->return_object), NULL); 24162306a36Sopenharmony_ci acpi_ex_exit_interpreter(); 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 24462306a36Sopenharmony_ci info->return_object = NULL; 24562306a36Sopenharmony_ci goto cleanup; 24662306a36Sopenharmony_ci } 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci ACPI_DEBUG_PRINT((ACPI_DB_NAMES, "Returned object %p [%s]\n", 24962306a36Sopenharmony_ci info->return_object, 25062306a36Sopenharmony_ci acpi_ut_get_object_type_name(info-> 25162306a36Sopenharmony_ci return_object))); 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci status = AE_CTRL_RETURN_VALUE; /* Always has a "return value" */ 25462306a36Sopenharmony_ci break; 25562306a36Sopenharmony_ci } 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci /* 25862306a36Sopenharmony_ci * For predefined names, check the return value against the ACPI 25962306a36Sopenharmony_ci * specification. Some incorrect return value types are repaired. 26062306a36Sopenharmony_ci */ 26162306a36Sopenharmony_ci (void)acpi_ns_check_return_value(info->node, info, info->param_count, 26262306a36Sopenharmony_ci status, &info->return_object); 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci /* Check if there is a return value that must be dealt with */ 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci if (status == AE_CTRL_RETURN_VALUE) { 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci /* If caller does not want the return value, delete it */ 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci if (info->flags & ACPI_IGNORE_RETURN_VALUE) { 27162306a36Sopenharmony_ci acpi_ut_remove_reference(info->return_object); 27262306a36Sopenharmony_ci info->return_object = NULL; 27362306a36Sopenharmony_ci } 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci /* Map AE_CTRL_RETURN_VALUE to AE_OK, we are done with it */ 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci status = AE_OK; 27862306a36Sopenharmony_ci } else if (ACPI_FAILURE(status)) { 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci /* If return_object exists, delete it */ 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci if (info->return_object) { 28362306a36Sopenharmony_ci acpi_ut_remove_reference(info->return_object); 28462306a36Sopenharmony_ci info->return_object = NULL; 28562306a36Sopenharmony_ci } 28662306a36Sopenharmony_ci } 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci ACPI_DEBUG_PRINT((ACPI_DB_NAMES, 28962306a36Sopenharmony_ci "*** Completed evaluation of object %s ***\n", 29062306a36Sopenharmony_ci info->relative_pathname)); 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_cicleanup: 29362306a36Sopenharmony_ci /* Optional object evaluation log */ 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci ACPI_DEBUG_PRINT_RAW((ACPI_DB_EVALUATION, 29662306a36Sopenharmony_ci "%-26s: %s\n", " Exit evaluation", 29762306a36Sopenharmony_ci &info->full_pathname[1])); 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci /* 30062306a36Sopenharmony_ci * Namespace was unlocked by the handling acpi_ns* function, so we 30162306a36Sopenharmony_ci * just free the pathname and return 30262306a36Sopenharmony_ci */ 30362306a36Sopenharmony_ci ACPI_FREE(info->full_pathname); 30462306a36Sopenharmony_ci info->full_pathname = NULL; 30562306a36Sopenharmony_ci return_ACPI_STATUS(status); 30662306a36Sopenharmony_ci} 307