Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
0002 /*******************************************************************************
0003  *
0004  * Module Name: dsmthdat - control method arguments and local variables
0005  *
0006  ******************************************************************************/
0007 
0008 #include <acpi/acpi.h>
0009 #include "accommon.h"
0010 #include "acdispat.h"
0011 #include "acnamesp.h"
0012 #include "acinterp.h"
0013 
0014 #define _COMPONENT          ACPI_DISPATCHER
0015 ACPI_MODULE_NAME("dsmthdat")
0016 
0017 /* Local prototypes */
0018 static void
0019 acpi_ds_method_data_delete_value(u8 type,
0020                  u32 index, struct acpi_walk_state *walk_state);
0021 
0022 static acpi_status
0023 acpi_ds_method_data_set_value(u8 type,
0024                   u32 index,
0025                   union acpi_operand_object *object,
0026                   struct acpi_walk_state *walk_state);
0027 
0028 #ifdef ACPI_OBSOLETE_FUNCTIONS
0029 acpi_object_type
0030 acpi_ds_method_data_get_type(u16 opcode,
0031                  u32 index, struct acpi_walk_state *walk_state);
0032 #endif
0033 
0034 /*******************************************************************************
0035  *
0036  * FUNCTION:    acpi_ds_method_data_init
0037  *
0038  * PARAMETERS:  walk_state          - Current walk state object
0039  *
0040  * RETURN:      Status
0041  *
0042  * DESCRIPTION: Initialize the data structures that hold the method's arguments
0043  *              and locals. The data struct is an array of namespace nodes for
0044  *              each - this allows ref_of and de_ref_of to work properly for these
0045  *              special data types.
0046  *
0047  * NOTES:       walk_state fields are initialized to zero by the
0048  *              ACPI_ALLOCATE_ZEROED().
0049  *
0050  *              A pseudo-Namespace Node is assigned to each argument and local
0051  *              so that ref_of() can return a pointer to the Node.
0052  *
0053  ******************************************************************************/
0054 
0055 void acpi_ds_method_data_init(struct acpi_walk_state *walk_state)
0056 {
0057     u32 i;
0058 
0059     ACPI_FUNCTION_TRACE(ds_method_data_init);
0060 
0061     /* Init the method arguments */
0062 
0063     for (i = 0; i < ACPI_METHOD_NUM_ARGS; i++) {
0064         ACPI_MOVE_32_TO_32(&walk_state->arguments[i].name,
0065                    NAMEOF_ARG_NTE);
0066 
0067         walk_state->arguments[i].name.integer |= (i << 24);
0068         walk_state->arguments[i].descriptor_type = ACPI_DESC_TYPE_NAMED;
0069         walk_state->arguments[i].type = ACPI_TYPE_ANY;
0070         walk_state->arguments[i].flags = ANOBJ_METHOD_ARG;
0071     }
0072 
0073     /* Init the method locals */
0074 
0075     for (i = 0; i < ACPI_METHOD_NUM_LOCALS; i++) {
0076         ACPI_MOVE_32_TO_32(&walk_state->local_variables[i].name,
0077                    NAMEOF_LOCAL_NTE);
0078 
0079         walk_state->local_variables[i].name.integer |= (i << 24);
0080         walk_state->local_variables[i].descriptor_type =
0081             ACPI_DESC_TYPE_NAMED;
0082         walk_state->local_variables[i].type = ACPI_TYPE_ANY;
0083         walk_state->local_variables[i].flags = ANOBJ_METHOD_LOCAL;
0084     }
0085 
0086     return_VOID;
0087 }
0088 
0089 /*******************************************************************************
0090  *
0091  * FUNCTION:    acpi_ds_method_data_delete_all
0092  *
0093  * PARAMETERS:  walk_state          - Current walk state object
0094  *
0095  * RETURN:      None
0096  *
0097  * DESCRIPTION: Delete method locals and arguments. Arguments are only
0098  *              deleted if this method was called from another method.
0099  *
0100  ******************************************************************************/
0101 
0102 void acpi_ds_method_data_delete_all(struct acpi_walk_state *walk_state)
0103 {
0104     u32 index;
0105 
0106     ACPI_FUNCTION_TRACE(ds_method_data_delete_all);
0107 
0108     /* Detach the locals */
0109 
0110     for (index = 0; index < ACPI_METHOD_NUM_LOCALS; index++) {
0111         if (walk_state->local_variables[index].object) {
0112             ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Deleting Local%u=%p\n",
0113                       index,
0114                       walk_state->local_variables[index].
0115                       object));
0116 
0117             /* Detach object (if present) and remove a reference */
0118 
0119             acpi_ns_detach_object(&walk_state->
0120                           local_variables[index]);
0121         }
0122     }
0123 
0124     /* Detach the arguments */
0125 
0126     for (index = 0; index < ACPI_METHOD_NUM_ARGS; index++) {
0127         if (walk_state->arguments[index].object) {
0128             ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Deleting Arg%u=%p\n",
0129                       index,
0130                       walk_state->arguments[index].object));
0131 
0132             /* Detach object (if present) and remove a reference */
0133 
0134             acpi_ns_detach_object(&walk_state->arguments[index]);
0135         }
0136     }
0137 
0138     return_VOID;
0139 }
0140 
0141 /*******************************************************************************
0142  *
0143  * FUNCTION:    acpi_ds_method_data_init_args
0144  *
0145  * PARAMETERS:  *params         - Pointer to a parameter list for the method
0146  *              max_param_count - The arg count for this method
0147  *              walk_state      - Current walk state object
0148  *
0149  * RETURN:      Status
0150  *
0151  * DESCRIPTION: Initialize arguments for a method. The parameter list is a list
0152  *              of ACPI operand objects, either null terminated or whose length
0153  *              is defined by max_param_count.
0154  *
0155  ******************************************************************************/
0156 
0157 acpi_status
0158 acpi_ds_method_data_init_args(union acpi_operand_object **params,
0159                   u32 max_param_count,
0160                   struct acpi_walk_state *walk_state)
0161 {
0162     acpi_status status;
0163     u32 index = 0;
0164 
0165     ACPI_FUNCTION_TRACE_PTR(ds_method_data_init_args, params);
0166 
0167     if (!params) {
0168         ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
0169                   "No parameter list passed to method\n"));
0170         return_ACPI_STATUS(AE_OK);
0171     }
0172 
0173     /* Copy passed parameters into the new method stack frame */
0174 
0175     while ((index < ACPI_METHOD_NUM_ARGS) &&
0176            (index < max_param_count) && params[index]) {
0177         /*
0178          * A valid parameter.
0179          * Store the argument in the method/walk descriptor.
0180          * Do not copy the arg in order to implement call by reference
0181          */
0182         status =
0183             acpi_ds_method_data_set_value(ACPI_REFCLASS_ARG, index,
0184                           params[index], walk_state);
0185         if (ACPI_FAILURE(status)) {
0186             return_ACPI_STATUS(status);
0187         }
0188 
0189         index++;
0190     }
0191 
0192     ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "%u args passed to method\n", index));
0193     return_ACPI_STATUS(AE_OK);
0194 }
0195 
0196 /*******************************************************************************
0197  *
0198  * FUNCTION:    acpi_ds_method_data_get_node
0199  *
0200  * PARAMETERS:  type                - Either ACPI_REFCLASS_LOCAL or
0201  *                                    ACPI_REFCLASS_ARG
0202  *              index               - Which Local or Arg whose type to get
0203  *              walk_state          - Current walk state object
0204  *              node                - Where the node is returned.
0205  *
0206  * RETURN:      Status and node
0207  *
0208  * DESCRIPTION: Get the Node associated with a local or arg.
0209  *
0210  ******************************************************************************/
0211 
0212 acpi_status
0213 acpi_ds_method_data_get_node(u8 type,
0214                  u32 index,
0215                  struct acpi_walk_state *walk_state,
0216                  struct acpi_namespace_node **node)
0217 {
0218     ACPI_FUNCTION_TRACE(ds_method_data_get_node);
0219 
0220     /*
0221      * Method Locals and Arguments are supported
0222      */
0223     switch (type) {
0224     case ACPI_REFCLASS_LOCAL:
0225 
0226         if (index > ACPI_METHOD_MAX_LOCAL) {
0227             ACPI_ERROR((AE_INFO,
0228                     "Local index %u is invalid (max %u)",
0229                     index, ACPI_METHOD_MAX_LOCAL));
0230             return_ACPI_STATUS(AE_AML_INVALID_INDEX);
0231         }
0232 
0233         /* Return a pointer to the pseudo-node */
0234 
0235         *node = &walk_state->local_variables[index];
0236         break;
0237 
0238     case ACPI_REFCLASS_ARG:
0239 
0240         if (index > ACPI_METHOD_MAX_ARG) {
0241             ACPI_ERROR((AE_INFO,
0242                     "Arg index %u is invalid (max %u)",
0243                     index, ACPI_METHOD_MAX_ARG));
0244             return_ACPI_STATUS(AE_AML_INVALID_INDEX);
0245         }
0246 
0247         /* Return a pointer to the pseudo-node */
0248 
0249         *node = &walk_state->arguments[index];
0250         break;
0251 
0252     default:
0253 
0254         ACPI_ERROR((AE_INFO, "Type %u is invalid", type));
0255         return_ACPI_STATUS(AE_TYPE);
0256     }
0257 
0258     return_ACPI_STATUS(AE_OK);
0259 }
0260 
0261 /*******************************************************************************
0262  *
0263  * FUNCTION:    acpi_ds_method_data_set_value
0264  *
0265  * PARAMETERS:  type                - Either ACPI_REFCLASS_LOCAL or
0266  *                                    ACPI_REFCLASS_ARG
0267  *              index               - Which Local or Arg to get
0268  *              object              - Object to be inserted into the stack entry
0269  *              walk_state          - Current walk state object
0270  *
0271  * RETURN:      Status
0272  *
0273  * DESCRIPTION: Insert an object onto the method stack at entry Opcode:Index.
0274  *              Note: There is no "implicit conversion" for locals.
0275  *
0276  ******************************************************************************/
0277 
0278 static acpi_status
0279 acpi_ds_method_data_set_value(u8 type,
0280                   u32 index,
0281                   union acpi_operand_object *object,
0282                   struct acpi_walk_state *walk_state)
0283 {
0284     acpi_status status;
0285     struct acpi_namespace_node *node;
0286 
0287     ACPI_FUNCTION_TRACE(ds_method_data_set_value);
0288 
0289     ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
0290               "NewObj %p Type %2.2X, Refs=%u [%s]\n", object,
0291               type, object->common.reference_count,
0292               acpi_ut_get_type_name(object->common.type)));
0293 
0294     /* Get the namespace node for the arg/local */
0295 
0296     status = acpi_ds_method_data_get_node(type, index, walk_state, &node);
0297     if (ACPI_FAILURE(status)) {
0298         return_ACPI_STATUS(status);
0299     }
0300 
0301     /*
0302      * Increment ref count so object can't be deleted while installed.
0303      * NOTE: We do not copy the object in order to preserve the call by
0304      * reference semantics of ACPI Control Method invocation.
0305      * (See ACPI Specification 2.0C)
0306      */
0307     acpi_ut_add_reference(object);
0308 
0309     /* Install the object */
0310 
0311     node->object = object;
0312     return_ACPI_STATUS(status);
0313 }
0314 
0315 /*******************************************************************************
0316  *
0317  * FUNCTION:    acpi_ds_method_data_get_value
0318  *
0319  * PARAMETERS:  type                - Either ACPI_REFCLASS_LOCAL or
0320  *                                    ACPI_REFCLASS_ARG
0321  *              index               - Which localVar or argument to get
0322  *              walk_state          - Current walk state object
0323  *              dest_desc           - Where Arg or Local value is returned
0324  *
0325  * RETURN:      Status
0326  *
0327  * DESCRIPTION: Retrieve value of selected Arg or Local for this method
0328  *              Used only in acpi_ex_resolve_to_value().
0329  *
0330  ******************************************************************************/
0331 
0332 acpi_status
0333 acpi_ds_method_data_get_value(u8 type,
0334                   u32 index,
0335                   struct acpi_walk_state *walk_state,
0336                   union acpi_operand_object **dest_desc)
0337 {
0338     acpi_status status;
0339     struct acpi_namespace_node *node;
0340     union acpi_operand_object *object;
0341 
0342     ACPI_FUNCTION_TRACE(ds_method_data_get_value);
0343 
0344     /* Validate the object descriptor */
0345 
0346     if (!dest_desc) {
0347         ACPI_ERROR((AE_INFO, "Null object descriptor pointer"));
0348         return_ACPI_STATUS(AE_BAD_PARAMETER);
0349     }
0350 
0351     /* Get the namespace node for the arg/local */
0352 
0353     status = acpi_ds_method_data_get_node(type, index, walk_state, &node);
0354     if (ACPI_FAILURE(status)) {
0355         return_ACPI_STATUS(status);
0356     }
0357 
0358     /* Get the object from the node */
0359 
0360     object = node->object;
0361 
0362     /* Examine the returned object, it must be valid. */
0363 
0364     if (!object) {
0365         /*
0366          * Index points to uninitialized object.
0367          * This means that either 1) The expected argument was
0368          * not passed to the method, or 2) A local variable
0369          * was referenced by the method (via the ASL)
0370          * before it was initialized. Either case is an error.
0371          */
0372 
0373         /* If slack enabled, init the local_x/arg_x to an Integer of value zero */
0374 
0375         if (acpi_gbl_enable_interpreter_slack) {
0376             object = acpi_ut_create_integer_object((u64) 0);
0377             if (!object) {
0378                 return_ACPI_STATUS(AE_NO_MEMORY);
0379             }
0380 
0381             node->object = object;
0382         }
0383 
0384         /* Otherwise, return the error */
0385 
0386         else
0387             switch (type) {
0388             case ACPI_REFCLASS_ARG:
0389 
0390                 ACPI_ERROR((AE_INFO,
0391                         "Uninitialized Arg[%u] at node %p",
0392                         index, node));
0393 
0394                 return_ACPI_STATUS(AE_AML_UNINITIALIZED_ARG);
0395 
0396             case ACPI_REFCLASS_LOCAL:
0397                 /*
0398                  * No error message for this case, will be trapped again later to
0399                  * detect and ignore cases of Store(local_x,local_x)
0400                  */
0401                 return_ACPI_STATUS(AE_AML_UNINITIALIZED_LOCAL);
0402 
0403             default:
0404 
0405                 ACPI_ERROR((AE_INFO,
0406                         "Not a Arg/Local opcode: 0x%X",
0407                         type));
0408                 return_ACPI_STATUS(AE_AML_INTERNAL);
0409             }
0410     }
0411 
0412     /*
0413      * The Index points to an initialized and valid object.
0414      * Return an additional reference to the object
0415      */
0416     *dest_desc = object;
0417     acpi_ut_add_reference(object);
0418 
0419     return_ACPI_STATUS(AE_OK);
0420 }
0421 
0422 /*******************************************************************************
0423  *
0424  * FUNCTION:    acpi_ds_method_data_delete_value
0425  *
0426  * PARAMETERS:  type                - Either ACPI_REFCLASS_LOCAL or
0427  *                                    ACPI_REFCLASS_ARG
0428  *              index               - Which localVar or argument to delete
0429  *              walk_state          - Current walk state object
0430  *
0431  * RETURN:      None
0432  *
0433  * DESCRIPTION: Delete the entry at Opcode:Index. Inserts
0434  *              a null into the stack slot after the object is deleted.
0435  *
0436  ******************************************************************************/
0437 
0438 static void
0439 acpi_ds_method_data_delete_value(u8 type,
0440                  u32 index, struct acpi_walk_state *walk_state)
0441 {
0442     acpi_status status;
0443     struct acpi_namespace_node *node;
0444     union acpi_operand_object *object;
0445 
0446     ACPI_FUNCTION_TRACE(ds_method_data_delete_value);
0447 
0448     /* Get the namespace node for the arg/local */
0449 
0450     status = acpi_ds_method_data_get_node(type, index, walk_state, &node);
0451     if (ACPI_FAILURE(status)) {
0452         return_VOID;
0453     }
0454 
0455     /* Get the associated object */
0456 
0457     object = acpi_ns_get_attached_object(node);
0458 
0459     /*
0460      * Undefine the Arg or Local by setting its descriptor
0461      * pointer to NULL. Locals/Args can contain both
0462      * ACPI_OPERAND_OBJECTS and ACPI_NAMESPACE_NODEs
0463      */
0464     node->object = NULL;
0465 
0466     if ((object) &&
0467         (ACPI_GET_DESCRIPTOR_TYPE(object) == ACPI_DESC_TYPE_OPERAND)) {
0468         /*
0469          * There is a valid object.
0470          * Decrement the reference count by one to balance the
0471          * increment when the object was stored.
0472          */
0473         acpi_ut_remove_reference(object);
0474     }
0475 
0476     return_VOID;
0477 }
0478 
0479 /*******************************************************************************
0480  *
0481  * FUNCTION:    acpi_ds_store_object_to_local
0482  *
0483  * PARAMETERS:  type                - Either ACPI_REFCLASS_LOCAL or
0484  *                                    ACPI_REFCLASS_ARG
0485  *              index               - Which Local or Arg to set
0486  *              obj_desc            - Value to be stored
0487  *              walk_state          - Current walk state
0488  *
0489  * RETURN:      Status
0490  *
0491  * DESCRIPTION: Store a value in an Arg or Local. The obj_desc is installed
0492  *              as the new value for the Arg or Local and the reference count
0493  *              for obj_desc is incremented.
0494  *
0495  ******************************************************************************/
0496 
0497 acpi_status
0498 acpi_ds_store_object_to_local(u8 type,
0499                   u32 index,
0500                   union acpi_operand_object *obj_desc,
0501                   struct acpi_walk_state *walk_state)
0502 {
0503     acpi_status status;
0504     struct acpi_namespace_node *node;
0505     union acpi_operand_object *current_obj_desc;
0506     union acpi_operand_object *new_obj_desc;
0507 
0508     ACPI_FUNCTION_TRACE(ds_store_object_to_local);
0509     ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Type=%2.2X Index=%u Obj=%p\n",
0510               type, index, obj_desc));
0511 
0512     /* Parameter validation */
0513 
0514     if (!obj_desc) {
0515         return_ACPI_STATUS(AE_BAD_PARAMETER);
0516     }
0517 
0518     /* Get the namespace node for the arg/local */
0519 
0520     status = acpi_ds_method_data_get_node(type, index, walk_state, &node);
0521     if (ACPI_FAILURE(status)) {
0522         return_ACPI_STATUS(status);
0523     }
0524 
0525     current_obj_desc = acpi_ns_get_attached_object(node);
0526     if (current_obj_desc == obj_desc) {
0527         ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Obj=%p already installed!\n",
0528                   obj_desc));
0529         return_ACPI_STATUS(status);
0530     }
0531 
0532     /*
0533      * If the reference count on the object is more than one, we must
0534      * take a copy of the object before we store. A reference count
0535      * of exactly 1 means that the object was just created during the
0536      * evaluation of an expression, and we can safely use it since it
0537      * is not used anywhere else.
0538      */
0539     new_obj_desc = obj_desc;
0540     if (obj_desc->common.reference_count > 1) {
0541         status =
0542             acpi_ut_copy_iobject_to_iobject(obj_desc, &new_obj_desc,
0543                             walk_state);
0544         if (ACPI_FAILURE(status)) {
0545             return_ACPI_STATUS(status);
0546         }
0547     }
0548 
0549     /*
0550      * If there is an object already in this slot, we either
0551      * have to delete it, or if this is an argument and there
0552      * is an object reference stored there, we have to do
0553      * an indirect store!
0554      */
0555     if (current_obj_desc) {
0556         /*
0557          * Check for an indirect store if an argument
0558          * contains an object reference (stored as an Node).
0559          * We don't allow this automatic dereferencing for
0560          * locals, since a store to a local should overwrite
0561          * anything there, including an object reference.
0562          *
0563          * If both Arg0 and Local0 contain ref_of (Local4):
0564          *
0565          * Store (1, Arg0)             - Causes indirect store to local4
0566          * Store (1, Local0)           - Stores 1 in local0, overwriting
0567          *                                  the reference to local4
0568          * Store (1, de_refof (Local0)) - Causes indirect store to local4
0569          *
0570          * Weird, but true.
0571          */
0572         if (type == ACPI_REFCLASS_ARG) {
0573             /*
0574              * If we have a valid reference object that came from ref_of(),
0575              * do the indirect store
0576              */
0577             if ((ACPI_GET_DESCRIPTOR_TYPE(current_obj_desc) ==
0578                  ACPI_DESC_TYPE_OPERAND) &&
0579                 (current_obj_desc->common.type ==
0580                  ACPI_TYPE_LOCAL_REFERENCE) &&
0581                 (current_obj_desc->reference.class ==
0582                  ACPI_REFCLASS_REFOF)) {
0583                 ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
0584                           "Arg (%p) is an ObjRef(Node), storing in node %p\n",
0585                           new_obj_desc,
0586                           current_obj_desc));
0587 
0588                 /*
0589                  * Store this object to the Node (perform the indirect store)
0590                  * NOTE: No implicit conversion is performed, as per the ACPI
0591                  * specification rules on storing to Locals/Args.
0592                  */
0593                 status =
0594                     acpi_ex_store_object_to_node(new_obj_desc,
0595                                  current_obj_desc->
0596                                  reference.
0597                                  object,
0598                                  walk_state,
0599                                  ACPI_NO_IMPLICIT_CONVERSION);
0600 
0601                 /* Remove local reference if we copied the object above */
0602 
0603                 if (new_obj_desc != obj_desc) {
0604                     acpi_ut_remove_reference(new_obj_desc);
0605                 }
0606 
0607                 return_ACPI_STATUS(status);
0608             }
0609         }
0610 
0611         /* Delete the existing object before storing the new one */
0612 
0613         acpi_ds_method_data_delete_value(type, index, walk_state);
0614     }
0615 
0616     /*
0617      * Install the Obj descriptor (*new_obj_desc) into
0618      * the descriptor for the Arg or Local.
0619      * (increments the object reference count by one)
0620      */
0621     status =
0622         acpi_ds_method_data_set_value(type, index, new_obj_desc,
0623                       walk_state);
0624 
0625     /* Remove local reference if we copied the object above */
0626 
0627     if (new_obj_desc != obj_desc) {
0628         acpi_ut_remove_reference(new_obj_desc);
0629     }
0630 
0631     return_ACPI_STATUS(status);
0632 }
0633 
0634 #ifdef ACPI_OBSOLETE_FUNCTIONS
0635 /*******************************************************************************
0636  *
0637  * FUNCTION:    acpi_ds_method_data_get_type
0638  *
0639  * PARAMETERS:  opcode              - Either AML_FIRST LOCAL_OP or
0640  *                                    AML_FIRST_ARG_OP
0641  *              index               - Which Local or Arg whose type to get
0642  *              walk_state          - Current walk state object
0643  *
0644  * RETURN:      Data type of current value of the selected Arg or Local
0645  *
0646  * DESCRIPTION: Get the type of the object stored in the Local or Arg
0647  *
0648  ******************************************************************************/
0649 
0650 acpi_object_type
0651 acpi_ds_method_data_get_type(u16 opcode,
0652                  u32 index, struct acpi_walk_state *walk_state)
0653 {
0654     acpi_status status;
0655     struct acpi_namespace_node *node;
0656     union acpi_operand_object *object;
0657 
0658     ACPI_FUNCTION_TRACE(ds_method_data_get_type);
0659 
0660     /* Get the namespace node for the arg/local */
0661 
0662     status = acpi_ds_method_data_get_node(opcode, index, walk_state, &node);
0663     if (ACPI_FAILURE(status)) {
0664         return_VALUE((ACPI_TYPE_NOT_FOUND));
0665     }
0666 
0667     /* Get the object */
0668 
0669     object = acpi_ns_get_attached_object(node);
0670     if (!object) {
0671 
0672         /* Uninitialized local/arg, return TYPE_ANY */
0673 
0674         return_VALUE(ACPI_TYPE_ANY);
0675     }
0676 
0677     /* Get the object type */
0678 
0679     return_VALUE(object->type);
0680 }
0681 #endif