// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.01/*******************************************************************************2*3* Module Name: dsmthdat - control method arguments and local variables4*5******************************************************************************/67#include <acpi/acpi.h>8#include "accommon.h"9#include "acdispat.h"10#include "acnamesp.h"11#include "acinterp.h"1213#define _COMPONENT ACPI_DISPATCHER14ACPI_MODULE_NAME("dsmthdat")1516/* Local prototypes */17static void18acpi_ds_method_data_delete_value(u8 type,19u32 index, struct acpi_walk_state *walk_state);2021static acpi_status22acpi_ds_method_data_set_value(u8 type,23u32 index,24union acpi_operand_object *object,25struct acpi_walk_state *walk_state);2627#ifdef ACPI_OBSOLETE_FUNCTIONS28acpi_object_type29acpi_ds_method_data_get_type(u16 opcode,30u32 index, struct acpi_walk_state *walk_state);31#endif3233/*******************************************************************************34*35* FUNCTION: acpi_ds_method_data_init36*37* PARAMETERS: walk_state - Current walk state object38*39* RETURN: Status40*41* DESCRIPTION: Initialize the data structures that hold the method's arguments42* and locals. The data struct is an array of namespace nodes for43* each - this allows ref_of and de_ref_of to work properly for these44* special data types.45*46* NOTES: walk_state fields are initialized to zero by the47* ACPI_ALLOCATE_ZEROED().48*49* A pseudo-Namespace Node is assigned to each argument and local50* so that ref_of() can return a pointer to the Node.51*52******************************************************************************/5354void acpi_ds_method_data_init(struct acpi_walk_state *walk_state)55{56u32 i;5758ACPI_FUNCTION_TRACE(ds_method_data_init);5960/* Init the method arguments */6162for (i = 0; i < ACPI_METHOD_NUM_ARGS; i++) {63ACPI_MOVE_32_TO_32(&walk_state->arguments[i].name,64NAMEOF_ARG_NTE);6566walk_state->arguments[i].name.integer |= (i << 24);67walk_state->arguments[i].descriptor_type = ACPI_DESC_TYPE_NAMED;68walk_state->arguments[i].type = ACPI_TYPE_ANY;69walk_state->arguments[i].flags = ANOBJ_METHOD_ARG;70}7172/* Init the method locals */7374for (i = 0; i < ACPI_METHOD_NUM_LOCALS; i++) {75ACPI_MOVE_32_TO_32(&walk_state->local_variables[i].name,76NAMEOF_LOCAL_NTE);7778walk_state->local_variables[i].name.integer |= (i << 24);79walk_state->local_variables[i].descriptor_type =80ACPI_DESC_TYPE_NAMED;81walk_state->local_variables[i].type = ACPI_TYPE_ANY;82walk_state->local_variables[i].flags = ANOBJ_METHOD_LOCAL;83}8485return_VOID;86}8788/*******************************************************************************89*90* FUNCTION: acpi_ds_method_data_delete_all91*92* PARAMETERS: walk_state - Current walk state object93*94* RETURN: None95*96* DESCRIPTION: Delete method locals and arguments. Arguments are only97* deleted if this method was called from another method.98*99******************************************************************************/100101void acpi_ds_method_data_delete_all(struct acpi_walk_state *walk_state)102{103u32 index;104105ACPI_FUNCTION_TRACE(ds_method_data_delete_all);106107/* Detach the locals */108109for (index = 0; index < ACPI_METHOD_NUM_LOCALS; index++) {110if (walk_state->local_variables[index].object) {111ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Deleting Local%u=%p\n",112index,113walk_state->local_variables[index].114object));115116/* Detach object (if present) and remove a reference */117118acpi_ns_detach_object(&walk_state->119local_variables[index]);120}121}122123/* Detach the arguments */124125for (index = 0; index < ACPI_METHOD_NUM_ARGS; index++) {126if (walk_state->arguments[index].object) {127ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Deleting Arg%u=%p\n",128index,129walk_state->arguments[index].object));130131/* Detach object (if present) and remove a reference */132133acpi_ns_detach_object(&walk_state->arguments[index]);134}135}136137return_VOID;138}139140/*******************************************************************************141*142* FUNCTION: acpi_ds_method_data_init_args143*144* PARAMETERS: *params - Pointer to a parameter list for the method145* max_param_count - The arg count for this method146* walk_state - Current walk state object147*148* RETURN: Status149*150* DESCRIPTION: Initialize arguments for a method. The parameter list is a list151* of ACPI operand objects, either null terminated or whose length152* is defined by max_param_count.153*154******************************************************************************/155156acpi_status157acpi_ds_method_data_init_args(union acpi_operand_object **params,158u32 max_param_count,159struct acpi_walk_state *walk_state)160{161acpi_status status;162u32 index = 0;163164ACPI_FUNCTION_TRACE_PTR(ds_method_data_init_args, params);165166if (!params) {167ACPI_DEBUG_PRINT((ACPI_DB_EXEC,168"No parameter list passed to method\n"));169return_ACPI_STATUS(AE_OK);170}171172/* Copy passed parameters into the new method stack frame */173174while ((index < ACPI_METHOD_NUM_ARGS) &&175(index < max_param_count) && params[index]) {176/*177* A valid parameter.178* Store the argument in the method/walk descriptor.179* Do not copy the arg in order to implement call by reference180*/181status =182acpi_ds_method_data_set_value(ACPI_REFCLASS_ARG, index,183params[index], walk_state);184if (ACPI_FAILURE(status)) {185return_ACPI_STATUS(status);186}187188index++;189}190acpi_ex_trace_args(params, index);191192ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "%u args passed to method\n", index));193return_ACPI_STATUS(AE_OK);194}195196/*******************************************************************************197*198* FUNCTION: acpi_ds_method_data_get_node199*200* PARAMETERS: type - Either ACPI_REFCLASS_LOCAL or201* ACPI_REFCLASS_ARG202* index - Which Local or Arg whose type to get203* walk_state - Current walk state object204* node - Where the node is returned.205*206* RETURN: Status and node207*208* DESCRIPTION: Get the Node associated with a local or arg.209*210******************************************************************************/211212acpi_status213acpi_ds_method_data_get_node(u8 type,214u32 index,215struct acpi_walk_state *walk_state,216struct acpi_namespace_node **node)217{218ACPI_FUNCTION_TRACE(ds_method_data_get_node);219220/*221* Method Locals and Arguments are supported222*/223switch (type) {224case ACPI_REFCLASS_LOCAL:225226if (index > ACPI_METHOD_MAX_LOCAL) {227ACPI_ERROR((AE_INFO,228"Local index %u is invalid (max %u)",229index, ACPI_METHOD_MAX_LOCAL));230return_ACPI_STATUS(AE_AML_INVALID_INDEX);231}232233/* Return a pointer to the pseudo-node */234235*node = &walk_state->local_variables[index];236break;237238case ACPI_REFCLASS_ARG:239240if (index > ACPI_METHOD_MAX_ARG) {241ACPI_ERROR((AE_INFO,242"Arg index %u is invalid (max %u)",243index, ACPI_METHOD_MAX_ARG));244return_ACPI_STATUS(AE_AML_INVALID_INDEX);245}246247/* Return a pointer to the pseudo-node */248249*node = &walk_state->arguments[index];250break;251252default:253254ACPI_ERROR((AE_INFO, "Type %u is invalid", type));255return_ACPI_STATUS(AE_TYPE);256}257258return_ACPI_STATUS(AE_OK);259}260261/*******************************************************************************262*263* FUNCTION: acpi_ds_method_data_set_value264*265* PARAMETERS: type - Either ACPI_REFCLASS_LOCAL or266* ACPI_REFCLASS_ARG267* index - Which Local or Arg to get268* object - Object to be inserted into the stack entry269* walk_state - Current walk state object270*271* RETURN: Status272*273* DESCRIPTION: Insert an object onto the method stack at entry Opcode:Index.274* Note: There is no "implicit conversion" for locals.275*276******************************************************************************/277278static acpi_status279acpi_ds_method_data_set_value(u8 type,280u32 index,281union acpi_operand_object *object,282struct acpi_walk_state *walk_state)283{284acpi_status status;285struct acpi_namespace_node *node;286287ACPI_FUNCTION_TRACE(ds_method_data_set_value);288289ACPI_DEBUG_PRINT((ACPI_DB_EXEC,290"NewObj %p Type %2.2X, Refs=%u [%s]\n", object,291type, object->common.reference_count,292acpi_ut_get_type_name(object->common.type)));293294/* Get the namespace node for the arg/local */295296status = acpi_ds_method_data_get_node(type, index, walk_state, &node);297if (ACPI_FAILURE(status)) {298return_ACPI_STATUS(status);299}300301/*302* Increment ref count so object can't be deleted while installed.303* NOTE: We do not copy the object in order to preserve the call by304* reference semantics of ACPI Control Method invocation.305* (See ACPI Specification 2.0C)306*/307acpi_ut_add_reference(object);308309/* Install the object */310311node->object = object;312return_ACPI_STATUS(status);313}314315/*******************************************************************************316*317* FUNCTION: acpi_ds_method_data_get_value318*319* PARAMETERS: type - Either ACPI_REFCLASS_LOCAL or320* ACPI_REFCLASS_ARG321* index - Which localVar or argument to get322* walk_state - Current walk state object323* dest_desc - Where Arg or Local value is returned324*325* RETURN: Status326*327* DESCRIPTION: Retrieve value of selected Arg or Local for this method328* Used only in acpi_ex_resolve_to_value().329*330******************************************************************************/331332acpi_status333acpi_ds_method_data_get_value(u8 type,334u32 index,335struct acpi_walk_state *walk_state,336union acpi_operand_object **dest_desc)337{338acpi_status status;339struct acpi_namespace_node *node;340union acpi_operand_object *object;341342ACPI_FUNCTION_TRACE(ds_method_data_get_value);343344/* Validate the object descriptor */345346if (!dest_desc) {347ACPI_ERROR((AE_INFO, "Null object descriptor pointer"));348return_ACPI_STATUS(AE_BAD_PARAMETER);349}350351/* Get the namespace node for the arg/local */352353status = acpi_ds_method_data_get_node(type, index, walk_state, &node);354if (ACPI_FAILURE(status)) {355return_ACPI_STATUS(status);356}357358/* Get the object from the node */359360object = node->object;361362/* Examine the returned object, it must be valid. */363364if (!object) {365/*366* Index points to uninitialized object.367* This means that either 1) The expected argument was368* not passed to the method, or 2) A local variable369* was referenced by the method (via the ASL)370* before it was initialized. Either case is an error.371*/372373/* If slack enabled, init the local_x/arg_x to an Integer of value zero */374375if (acpi_gbl_enable_interpreter_slack) {376object = acpi_ut_create_integer_object((u64) 0);377if (!object) {378return_ACPI_STATUS(AE_NO_MEMORY);379}380381node->object = object;382}383384/* Otherwise, return the error */385386else387switch (type) {388case ACPI_REFCLASS_ARG:389390ACPI_ERROR((AE_INFO,391"Uninitialized Arg[%u] at node %p",392index, node));393394return_ACPI_STATUS(AE_AML_UNINITIALIZED_ARG);395396case ACPI_REFCLASS_LOCAL:397/*398* No error message for this case, will be trapped again later to399* detect and ignore cases of Store(local_x,local_x)400*/401return_ACPI_STATUS(AE_AML_UNINITIALIZED_LOCAL);402403default:404405ACPI_ERROR((AE_INFO,406"Not a Arg/Local opcode: 0x%X",407type));408return_ACPI_STATUS(AE_AML_INTERNAL);409}410}411412/*413* The Index points to an initialized and valid object.414* Return an additional reference to the object415*/416*dest_desc = object;417acpi_ut_add_reference(object);418419return_ACPI_STATUS(AE_OK);420}421422/*******************************************************************************423*424* FUNCTION: acpi_ds_method_data_delete_value425*426* PARAMETERS: type - Either ACPI_REFCLASS_LOCAL or427* ACPI_REFCLASS_ARG428* index - Which localVar or argument to delete429* walk_state - Current walk state object430*431* RETURN: None432*433* DESCRIPTION: Delete the entry at Opcode:Index. Inserts434* a null into the stack slot after the object is deleted.435*436******************************************************************************/437438static void439acpi_ds_method_data_delete_value(u8 type,440u32 index, struct acpi_walk_state *walk_state)441{442acpi_status status;443struct acpi_namespace_node *node;444union acpi_operand_object *object;445446ACPI_FUNCTION_TRACE(ds_method_data_delete_value);447448/* Get the namespace node for the arg/local */449450status = acpi_ds_method_data_get_node(type, index, walk_state, &node);451if (ACPI_FAILURE(status)) {452return_VOID;453}454455/* Get the associated object */456457object = acpi_ns_get_attached_object(node);458459/*460* Undefine the Arg or Local by setting its descriptor461* pointer to NULL. Locals/Args can contain both462* ACPI_OPERAND_OBJECTS and ACPI_NAMESPACE_NODEs463*/464node->object = NULL;465466if ((object) &&467(ACPI_GET_DESCRIPTOR_TYPE(object) == ACPI_DESC_TYPE_OPERAND)) {468/*469* There is a valid object.470* Decrement the reference count by one to balance the471* increment when the object was stored.472*/473acpi_ut_remove_reference(object);474}475476return_VOID;477}478479/*******************************************************************************480*481* FUNCTION: acpi_ds_store_object_to_local482*483* PARAMETERS: type - Either ACPI_REFCLASS_LOCAL or484* ACPI_REFCLASS_ARG485* index - Which Local or Arg to set486* obj_desc - Value to be stored487* walk_state - Current walk state488*489* RETURN: Status490*491* DESCRIPTION: Store a value in an Arg or Local. The obj_desc is installed492* as the new value for the Arg or Local and the reference count493* for obj_desc is incremented.494*495******************************************************************************/496497acpi_status498acpi_ds_store_object_to_local(u8 type,499u32 index,500union acpi_operand_object *obj_desc,501struct acpi_walk_state *walk_state)502{503acpi_status status;504struct acpi_namespace_node *node;505union acpi_operand_object *current_obj_desc;506union acpi_operand_object *new_obj_desc;507508ACPI_FUNCTION_TRACE(ds_store_object_to_local);509ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Type=%2.2X Index=%u Obj=%p\n",510type, index, obj_desc));511512/* Parameter validation */513514if (!obj_desc) {515return_ACPI_STATUS(AE_BAD_PARAMETER);516}517518/* Get the namespace node for the arg/local */519520status = acpi_ds_method_data_get_node(type, index, walk_state, &node);521if (ACPI_FAILURE(status)) {522return_ACPI_STATUS(status);523}524525current_obj_desc = acpi_ns_get_attached_object(node);526if (current_obj_desc == obj_desc) {527ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Obj=%p already installed!\n",528obj_desc));529return_ACPI_STATUS(status);530}531532/*533* If the reference count on the object is more than one, we must534* take a copy of the object before we store. A reference count535* of exactly 1 means that the object was just created during the536* evaluation of an expression, and we can safely use it since it537* is not used anywhere else.538*/539new_obj_desc = obj_desc;540if (obj_desc->common.reference_count > 1) {541status =542acpi_ut_copy_iobject_to_iobject(obj_desc, &new_obj_desc,543walk_state);544if (ACPI_FAILURE(status)) {545return_ACPI_STATUS(status);546}547}548549/*550* If there is an object already in this slot, we either551* have to delete it, or if this is an argument and there552* is an object reference stored there, we have to do553* an indirect store!554*/555if (current_obj_desc) {556/*557* Check for an indirect store if an argument558* contains an object reference (stored as an Node).559* We don't allow this automatic dereferencing for560* locals, since a store to a local should overwrite561* anything there, including an object reference.562*563* If both Arg0 and Local0 contain ref_of (Local4):564*565* Store (1, Arg0) - Causes indirect store to local4566* Store (1, Local0) - Stores 1 in local0, overwriting567* the reference to local4568* Store (1, de_refof (Local0)) - Causes indirect store to local4569*570* Weird, but true.571*/572if (type == ACPI_REFCLASS_ARG) {573/*574* If we have a valid reference object that came from ref_of(),575* do the indirect store576*/577if ((ACPI_GET_DESCRIPTOR_TYPE(current_obj_desc) ==578ACPI_DESC_TYPE_OPERAND) &&579(current_obj_desc->common.type ==580ACPI_TYPE_LOCAL_REFERENCE) &&581(current_obj_desc->reference.class ==582ACPI_REFCLASS_REFOF)) {583ACPI_DEBUG_PRINT((ACPI_DB_EXEC,584"Arg (%p) is an ObjRef(Node), storing in node %p\n",585new_obj_desc,586current_obj_desc));587588/*589* Store this object to the Node (perform the indirect store)590* NOTE: No implicit conversion is performed, as per the ACPI591* specification rules on storing to Locals/Args.592*/593status =594acpi_ex_store_object_to_node(new_obj_desc,595current_obj_desc->596reference.597object,598walk_state,599ACPI_NO_IMPLICIT_CONVERSION);600601/* Remove local reference if we copied the object above */602603if (new_obj_desc != obj_desc) {604acpi_ut_remove_reference(new_obj_desc);605}606607return_ACPI_STATUS(status);608}609}610611/* Delete the existing object before storing the new one */612613acpi_ds_method_data_delete_value(type, index, walk_state);614}615616/*617* Install the Obj descriptor (*new_obj_desc) into618* the descriptor for the Arg or Local.619* (increments the object reference count by one)620*/621status =622acpi_ds_method_data_set_value(type, index, new_obj_desc,623walk_state);624625/* Remove local reference if we copied the object above */626627if (new_obj_desc != obj_desc) {628acpi_ut_remove_reference(new_obj_desc);629}630631return_ACPI_STATUS(status);632}633634#ifdef ACPI_OBSOLETE_FUNCTIONS635/*******************************************************************************636*637* FUNCTION: acpi_ds_method_data_get_type638*639* PARAMETERS: opcode - Either AML_FIRST LOCAL_OP or640* AML_FIRST_ARG_OP641* index - Which Local or Arg whose type to get642* walk_state - Current walk state object643*644* RETURN: Data type of current value of the selected Arg or Local645*646* DESCRIPTION: Get the type of the object stored in the Local or Arg647*648******************************************************************************/649650acpi_object_type651acpi_ds_method_data_get_type(u16 opcode,652u32 index, struct acpi_walk_state *walk_state)653{654acpi_status status;655struct acpi_namespace_node *node;656union acpi_operand_object *object;657658ACPI_FUNCTION_TRACE(ds_method_data_get_type);659660/* Get the namespace node for the arg/local */661662status = acpi_ds_method_data_get_node(opcode, index, walk_state, &node);663if (ACPI_FAILURE(status)) {664return_VALUE((ACPI_TYPE_NOT_FOUND));665}666667/* Get the object */668669object = acpi_ns_get_attached_object(node);670if (!object) {671672/* Uninitialized local/arg, return TYPE_ANY */673674return_VALUE(ACPI_TYPE_ANY);675}676677/* Get the object type */678679return_VALUE(object->type);680}681#endif682683684