1 /*******************************************************************************
   2  *
   3  * Module Name: nseval - Object evaluation, includes control method execution
   4  *
   5  ******************************************************************************/
   6 
   7 /*
   8  * Copyright (C) 2000 - 2011, Intel Corp.
   9  * All rights reserved.
  10  *
  11  * Redistribution and use in source and binary forms, with or without
  12  * modification, are permitted provided that the following conditions
  13  * are met:
  14  * 1. Redistributions of source code must retain the above copyright
  15  *    notice, this list of conditions, and the following disclaimer,
  16  *    without modification.
  17  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
  18  *    substantially similar to the "NO WARRANTY" disclaimer below
  19  *    ("Disclaimer") and any redistribution must be conditioned upon
  20  *    including a substantially similar Disclaimer requirement for further
  21  *    binary redistribution.
  22  * 3. Neither the names of the above-listed copyright holders nor the names
  23  *    of any contributors may be used to endorse or promote products derived
  24  *    from this software without specific prior written permission.
  25  *
  26  * Alternatively, this software may be distributed under the terms of the
  27  * GNU General Public License ("GPL") version 2 as published by the Free
  28  * Software Foundation.
  29  *
  30  * NO WARRANTY
  31  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  32  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  33  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
  34  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  35  * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  36  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  37  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  38  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  39  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
  40  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  41  * POSSIBILITY OF SUCH DAMAGES.
  42  */
  43 
  44 #define __NSEVAL_C__
  45 
  46 #include "acpi.h"
  47 #include "accommon.h"
  48 #include "acparser.h"
  49 #include "acinterp.h"
  50 #include "acnamesp.h"
  51 
  52 
  53 #define _COMPONENT          ACPI_NAMESPACE
  54         ACPI_MODULE_NAME    ("nseval")
  55 
  56 /* Local prototypes */
  57 
  58 static void
  59 AcpiNsExecModuleCode (
  60     ACPI_OPERAND_OBJECT     *MethodObj,
  61     ACPI_EVALUATE_INFO      *Info);
  62 
  63 
  64 /*******************************************************************************
  65  *
  66  * FUNCTION:    AcpiNsEvaluate
  67  *
  68  * PARAMETERS:  Info            - Evaluation info block, contains:
  69  *                  PrefixNode      - Prefix or Method/Object Node to execute
  70  *                  Pathname        - Name of method to execute, If NULL, the
  71  *                                    Node is the object to execute
  72  *                  Parameters      - List of parameters to pass to the method,
  73  *                                    terminated by NULL. Params itself may be
  74  *                                    NULL if no parameters are being passed.
  75  *                  ReturnObject    - Where to put method's return value (if
  76  *                                    any). If NULL, no value is returned.
  77  *                  ParameterType   - Type of Parameter list
  78  *                  ReturnObject    - Where to put method's return value (if
  79  *                                    any). If NULL, no value is returned.
  80  *                  Flags           - ACPI_IGNORE_RETURN_VALUE to delete return
  81  *
  82  * RETURN:      Status
  83  *
  84  * DESCRIPTION: Execute a control method or return the current value of an
  85  *              ACPI namespace object.
  86  *
  87  * MUTEX:       Locks interpreter
  88  *
  89  ******************************************************************************/
  90 
  91 ACPI_STATUS
  92 AcpiNsEvaluate (
  93     ACPI_EVALUATE_INFO      *Info)
  94 {
  95     ACPI_STATUS             Status;
  96     ACPI_NAMESPACE_NODE     *Node;
  97 
  98 
  99     ACPI_FUNCTION_TRACE (NsEvaluate);
 100 
 101 
 102     if (!Info)
 103     {
 104         return_ACPI_STATUS (AE_BAD_PARAMETER);
 105     }
 106 
 107     /* Initialize the return value to an invalid object */
 108 
 109     Info->ReturnObject = NULL;
 110     Info->ParamCount = 0;
 111 
 112     /*
 113      * Get the actual namespace node for the target object. Handles these cases:
 114      *
 115      * 1) Null node, Pathname (absolute path)
 116      * 2) Node, Pathname (path relative to Node)
 117      * 3) Node, Null Pathname
 118      */
 119     Status = AcpiNsGetNode (Info->PrefixNode, Info->Pathname,
 120                 ACPI_NS_NO_UPSEARCH, &Info->ResolvedNode);
 121     if (ACPI_FAILURE (Status))
 122     {
 123         return_ACPI_STATUS (Status);
 124     }
 125 
 126     /*
 127      * For a method alias, we must grab the actual method node so that proper
 128      * scoping context will be established before execution.
 129      */
 130     if (AcpiNsGetType (Info->ResolvedNode) == ACPI_TYPE_LOCAL_METHOD_ALIAS)
 131     {
 132         Info->ResolvedNode =
 133             ACPI_CAST_PTR (ACPI_NAMESPACE_NODE, Info->ResolvedNode->Object);
 134     }
 135 
 136     ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, "%s [%p] Value %p\n", Info->Pathname,
 137         Info->ResolvedNode, AcpiNsGetAttachedObject (Info->ResolvedNode)));
 138 
 139     Node = Info->ResolvedNode;
 140 
 141     /*
 142      * Two major cases here:
 143      *
 144      * 1) The object is a control method -- execute it
 145      * 2) The object is not a method -- just return it's current value
 146      */
 147     if (AcpiNsGetType (Info->ResolvedNode) == ACPI_TYPE_METHOD)
 148     {
 149         /*
 150          * 1) Object is a control method - execute it
 151          */
 152 
 153         /* Verify that there is a method object associated with this node */
 154 
 155         Info->ObjDesc = AcpiNsGetAttachedObject (Info->ResolvedNode);
 156         if (!Info->ObjDesc)
 157         {
 158             ACPI_ERROR ((AE_INFO, "Control method has no attached sub-object"));
 159             return_ACPI_STATUS (AE_NULL_OBJECT);
 160         }
 161 
 162         /* Count the number of arguments being passed to the method */
 163 
 164         if (Info->Parameters)
 165         {
 166             while (Info->Parameters[Info->ParamCount])
 167             {
 168                 if (Info->ParamCount > ACPI_METHOD_MAX_ARG)
 169                 {
 170                     return_ACPI_STATUS (AE_LIMIT);
 171                 }
 172                 Info->ParamCount++;
 173             }
 174         }
 175 
 176         ACPI_DUMP_PATHNAME (Info->ResolvedNode, "ACPI: Execute Method",
 177             ACPI_LV_INFO, _COMPONENT);
 178 
 179         ACPI_DEBUG_PRINT ((ACPI_DB_EXEC,
 180             "Method at AML address %p Length %X\n",
 181             Info->ObjDesc->Method.AmlStart + 1,
 182             Info->ObjDesc->Method.AmlLength - 1));
 183 
 184         /*
 185          * Any namespace deletion must acquire both the namespace and
 186          * interpreter locks to ensure that no thread is using the portion of
 187          * the namespace that is being deleted.
 188          *
 189          * Execute the method via the interpreter. The interpreter is locked
 190          * here before calling into the AML parser
 191          */
 192         AcpiExEnterInterpreter ();
 193         Status = AcpiPsExecuteMethod (Info);
 194         AcpiExExitInterpreter ();
 195     }
 196     else
 197     {
 198         /*
 199          * 2) Object is not a method, return its current value
 200          *
 201          * Disallow certain object types. For these, "evaluation" is undefined.
 202          */
 203         switch (Info->ResolvedNode->Type)
 204         {
 205         case ACPI_TYPE_DEVICE:
 206         case ACPI_TYPE_EVENT:
 207         case ACPI_TYPE_MUTEX:
 208         case ACPI_TYPE_REGION:
 209         case ACPI_TYPE_THERMAL:
 210         case ACPI_TYPE_LOCAL_SCOPE:
 211 
 212             ACPI_ERROR ((AE_INFO,
 213                 "[%4.4s] Evaluation of object type [%s] is not supported",
 214                 Info->ResolvedNode->Name.Ascii,
 215                 AcpiUtGetTypeName (Info->ResolvedNode->Type)));
 216 
 217             return_ACPI_STATUS (AE_TYPE);
 218 
 219         default:
 220             break;
 221         }
 222 
 223         /*
 224          * Objects require additional resolution steps (e.g., the Node may be
 225          * a field that must be read, etc.) -- we can't just grab the object
 226          * out of the node.
 227          *
 228          * Use ResolveNodeToValue() to get the associated value.
 229          *
 230          * NOTE: we can get away with passing in NULL for a walk state because
 231          * ResolvedNode is guaranteed to not be a reference to either a method
 232          * local or a method argument (because this interface is never called
 233          * from a running method.)
 234          *
 235          * Even though we do not directly invoke the interpreter for object
 236          * resolution, we must lock it because we could access an opregion.
 237          * The opregion access code assumes that the interpreter is locked.
 238          */
 239         AcpiExEnterInterpreter ();
 240 
 241         /* Function has a strange interface */
 242 
 243         Status = AcpiExResolveNodeToValue (&Info->ResolvedNode, NULL);
 244         AcpiExExitInterpreter ();
 245 
 246         /*
 247          * If AcpiExResolveNodeToValue() succeeded, the return value was placed
 248          * in ResolvedNode.
 249          */
 250         if (ACPI_SUCCESS (Status))
 251         {
 252             Status = AE_CTRL_RETURN_VALUE;
 253             Info->ReturnObject =
 254                 ACPI_CAST_PTR (ACPI_OPERAND_OBJECT, Info->ResolvedNode);
 255 
 256             ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, "Returning object %p [%s]\n",
 257                 Info->ReturnObject,
 258                 AcpiUtGetObjectTypeName (Info->ReturnObject)));
 259         }
 260     }
 261 
 262     /*
 263      * Check input argument count against the ASL-defined count for a method.
 264      * Also check predefined names: argument count and return value against
 265      * the ACPI specification. Some incorrect return value types are repaired.
 266      */
 267     (void) AcpiNsCheckPredefinedNames (Node, Info->ParamCount,
 268                 Status, &Info->ReturnObject);
 269 
 270     /* Check if there is a return value that must be dealt with */
 271 
 272     if (Status == AE_CTRL_RETURN_VALUE)
 273     {
 274         /* If caller does not want the return value, delete it */
 275 
 276         if (Info->Flags & ACPI_IGNORE_RETURN_VALUE)
 277         {
 278             AcpiUtRemoveReference (Info->ReturnObject);
 279             Info->ReturnObject = NULL;
 280         }
 281 
 282         /* Map AE_CTRL_RETURN_VALUE to AE_OK, we are done with it */
 283 
 284         Status = AE_OK;
 285     }
 286 
 287     ACPI_DEBUG_PRINT ((ACPI_DB_NAMES,
 288         "*** Completed evaluation of object %s ***\n", Info->Pathname));
 289 
 290     /*
 291      * Namespace was unlocked by the handling AcpiNs* function, so we
 292      * just return
 293      */
 294     return_ACPI_STATUS (Status);
 295 }
 296 
 297 
 298 /*******************************************************************************
 299  *
 300  * FUNCTION:    AcpiNsExecModuleCodeList
 301  *
 302  * PARAMETERS:  None
 303  *
 304  * RETURN:      None. Exceptions during method execution are ignored, since
 305  *              we cannot abort a table load.
 306  *
 307  * DESCRIPTION: Execute all elements of the global module-level code list.
 308  *              Each element is executed as a single control method.
 309  *
 310  ******************************************************************************/
 311 
 312 void
 313 AcpiNsExecModuleCodeList (
 314     void)
 315 {
 316     ACPI_OPERAND_OBJECT     *Prev;
 317     ACPI_OPERAND_OBJECT     *Next;
 318     ACPI_EVALUATE_INFO      *Info;
 319     UINT32                  MethodCount = 0;
 320 
 321 
 322     ACPI_FUNCTION_TRACE (NsExecModuleCodeList);
 323 
 324 
 325     /* Exit now if the list is empty */
 326 
 327     Next = AcpiGbl_ModuleCodeList;
 328     if (!Next)
 329     {
 330         return_VOID;
 331     }
 332 
 333     /* Allocate the evaluation information block */
 334 
 335     Info = ACPI_ALLOCATE (sizeof (ACPI_EVALUATE_INFO));
 336     if (!Info)
 337     {
 338         return_VOID;
 339     }
 340 
 341     /* Walk the list, executing each "method" */
 342 
 343     while (Next)
 344     {
 345         Prev = Next;
 346         Next = Next->Method.Mutex;
 347 
 348         /* Clear the link field and execute the method */
 349 
 350         Prev->Method.Mutex = NULL;
 351         AcpiNsExecModuleCode (Prev, Info);
 352         MethodCount++;
 353 
 354         /* Delete the (temporary) method object */
 355 
 356         AcpiUtRemoveReference (Prev);
 357     }
 358 
 359     ACPI_INFO ((AE_INFO,
 360         "Executed %u blocks of module-level executable AML code",
 361         MethodCount));
 362 
 363     ACPI_FREE (Info);
 364     AcpiGbl_ModuleCodeList = NULL;
 365     return_VOID;
 366 }
 367 
 368 
 369 /*******************************************************************************
 370  *
 371  * FUNCTION:    AcpiNsExecModuleCode
 372  *
 373  * PARAMETERS:  MethodObj           - Object container for the module-level code
 374  *              Info                - Info block for method evaluation
 375  *
 376  * RETURN:      None. Exceptions during method execution are ignored, since
 377  *              we cannot abort a table load.
 378  *
 379  * DESCRIPTION: Execute a control method containing a block of module-level
 380  *              executable AML code. The control method is temporarily
 381  *              installed to the root node, then evaluated.
 382  *
 383  ******************************************************************************/
 384 
 385 static void
 386 AcpiNsExecModuleCode (
 387     ACPI_OPERAND_OBJECT     *MethodObj,
 388     ACPI_EVALUATE_INFO      *Info)
 389 {
 390     ACPI_OPERAND_OBJECT     *ParentObj;
 391     ACPI_NAMESPACE_NODE     *ParentNode;
 392     ACPI_OBJECT_TYPE        Type;
 393     ACPI_STATUS             Status;
 394 
 395 
 396     ACPI_FUNCTION_TRACE (NsExecModuleCode);
 397 
 398 
 399     /*
 400      * Get the parent node. We cheat by using the NextObject field
 401      * of the method object descriptor.
 402      */
 403     ParentNode = ACPI_CAST_PTR (ACPI_NAMESPACE_NODE,
 404                     MethodObj->Method.NextObject);
 405     Type = AcpiNsGetType (ParentNode);
 406 
 407     /*
 408      * Get the region handler and save it in the method object. We may need
 409      * this if an operation region declaration causes a _REG method to be run.
 410      *
 411      * We can't do this in AcpiPsLinkModuleCode because
 412      * AcpiGbl_RootNode->Object is NULL at PASS1.
 413      */
 414     if ((Type == ACPI_TYPE_DEVICE) && ParentNode->Object)
 415     {
 416         MethodObj->Method.Dispatch.Handler =
 417             ParentNode->Object->Device.Handler;
 418     }
 419 
 420     /* Must clear NextObject (AcpiNsAttachObject needs the field) */
 421 
 422     MethodObj->Method.NextObject = NULL;
 423 
 424     /* Initialize the evaluation information block */
 425 
 426     ACPI_MEMSET (Info, 0, sizeof (ACPI_EVALUATE_INFO));
 427     Info->PrefixNode = ParentNode;
 428 
 429     /*
 430      * Get the currently attached parent object. Add a reference, because the
 431      * ref count will be decreased when the method object is installed to
 432      * the parent node.
 433      */
 434     ParentObj = AcpiNsGetAttachedObject (ParentNode);
 435     if (ParentObj)
 436     {
 437         AcpiUtAddReference (ParentObj);
 438     }
 439 
 440     /* Install the method (module-level code) in the parent node */
 441 
 442     Status = AcpiNsAttachObject (ParentNode, MethodObj,
 443                 ACPI_TYPE_METHOD);
 444     if (ACPI_FAILURE (Status))
 445     {
 446         goto Exit;
 447     }
 448 
 449     /* Execute the parent node as a control method */
 450 
 451     Status = AcpiNsEvaluate (Info);
 452 
 453     ACPI_DEBUG_PRINT ((ACPI_DB_INIT, "Executed module-level code at %p\n",
 454         MethodObj->Method.AmlStart));
 455 
 456     /* Delete a possible implicit return value (in slack mode) */
 457 
 458     if (Info->ReturnObject)
 459     {
 460         AcpiUtRemoveReference (Info->ReturnObject);
 461     }
 462 
 463     /* Detach the temporary method object */
 464 
 465     AcpiNsDetachObject (ParentNode);
 466 
 467     /* Restore the original parent object */
 468 
 469     if (ParentObj)
 470     {
 471         Status = AcpiNsAttachObject (ParentNode, ParentObj, Type);
 472     }
 473     else
 474     {
 475         ParentNode->Type = (UINT8) Type;
 476     }
 477 
 478 Exit:
 479     if (ParentObj)
 480     {
 481         AcpiUtRemoveReference (ParentObj);
 482     }
 483     return_VOID;
 484 }
 485