1 /******************************************************************************
   2  *
   3  * Module Name: exresolv - AML Interpreter object resolution
   4  *
   5  *****************************************************************************/
   6 
   7 /*
   8  * Copyright (C) 2000 - 2013, 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 __EXRESOLV_C__
  45 
  46 #include "acpi.h"
  47 #include "accommon.h"
  48 #include "amlcode.h"
  49 #include "acdispat.h"
  50 #include "acinterp.h"
  51 #include "acnamesp.h"
  52 
  53 
  54 #define _COMPONENT          ACPI_EXECUTER
  55         ACPI_MODULE_NAME    ("exresolv")
  56 
  57 /* Local prototypes */
  58 
  59 static ACPI_STATUS
  60 AcpiExResolveObjectToValue (
  61     ACPI_OPERAND_OBJECT     **StackPtr,
  62     ACPI_WALK_STATE         *WalkState);
  63 
  64 
  65 /*******************************************************************************
  66  *
  67  * FUNCTION:    AcpiExResolveToValue
  68  *
  69  * PARAMETERS:  **StackPtr          - Points to entry on ObjStack, which can
  70  *                                    be either an (ACPI_OPERAND_OBJECT *)
  71  *                                    or an ACPI_HANDLE.
  72  *              WalkState           - Current method state
  73  *
  74  * RETURN:      Status
  75  *
  76  * DESCRIPTION: Convert Reference objects to values
  77  *
  78  ******************************************************************************/
  79 
  80 ACPI_STATUS
  81 AcpiExResolveToValue (
  82     ACPI_OPERAND_OBJECT     **StackPtr,
  83     ACPI_WALK_STATE         *WalkState)
  84 {
  85     ACPI_STATUS             Status;
  86 
  87 
  88     ACPI_FUNCTION_TRACE_PTR (ExResolveToValue, StackPtr);
  89 
  90 
  91     if (!StackPtr || !*StackPtr)
  92     {
  93         ACPI_ERROR ((AE_INFO, "Internal - null pointer"));
  94         return_ACPI_STATUS (AE_AML_NO_OPERAND);
  95     }
  96 
  97     /*
  98      * The entity pointed to by the StackPtr can be either
  99      * 1) A valid ACPI_OPERAND_OBJECT, or
 100      * 2) A ACPI_NAMESPACE_NODE (NamedObj)
 101      */
 102     if (ACPI_GET_DESCRIPTOR_TYPE (*StackPtr) == ACPI_DESC_TYPE_OPERAND)
 103     {
 104         Status = AcpiExResolveObjectToValue (StackPtr, WalkState);
 105         if (ACPI_FAILURE (Status))
 106         {
 107             return_ACPI_STATUS (Status);
 108         }
 109 
 110         if (!*StackPtr)
 111         {
 112             ACPI_ERROR ((AE_INFO, "Internal - null pointer"));
 113             return_ACPI_STATUS (AE_AML_NO_OPERAND);
 114         }
 115     }
 116 
 117     /*
 118      * Object on the stack may have changed if AcpiExResolveObjectToValue()
 119      * was called (i.e., we can't use an _else_ here.)
 120      */
 121     if (ACPI_GET_DESCRIPTOR_TYPE (*StackPtr) == ACPI_DESC_TYPE_NAMED)
 122     {
 123         Status = AcpiExResolveNodeToValue (
 124                         ACPI_CAST_INDIRECT_PTR (ACPI_NAMESPACE_NODE, StackPtr),
 125                         WalkState);
 126         if (ACPI_FAILURE (Status))
 127         {
 128             return_ACPI_STATUS (Status);
 129         }
 130     }
 131 
 132     ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Resolved object %p\n", *StackPtr));
 133     return_ACPI_STATUS (AE_OK);
 134 }
 135 
 136 
 137 /*******************************************************************************
 138  *
 139  * FUNCTION:    AcpiExResolveObjectToValue
 140  *
 141  * PARAMETERS:  StackPtr        - Pointer to an internal object
 142  *              WalkState       - Current method state
 143  *
 144  * RETURN:      Status
 145  *
 146  * DESCRIPTION: Retrieve the value from an internal object. The Reference type
 147  *              uses the associated AML opcode to determine the value.
 148  *
 149  ******************************************************************************/
 150 
 151 static ACPI_STATUS
 152 AcpiExResolveObjectToValue (
 153     ACPI_OPERAND_OBJECT     **StackPtr,
 154     ACPI_WALK_STATE         *WalkState)
 155 {
 156     ACPI_STATUS             Status = AE_OK;
 157     ACPI_OPERAND_OBJECT     *StackDesc;
 158     ACPI_OPERAND_OBJECT     *ObjDesc = NULL;
 159     UINT8                   RefType;
 160 
 161 
 162     ACPI_FUNCTION_TRACE (ExResolveObjectToValue);
 163 
 164 
 165     StackDesc = *StackPtr;
 166 
 167     /* This is an object of type ACPI_OPERAND_OBJECT */
 168 
 169     switch (StackDesc->Common.Type)
 170     {
 171     case ACPI_TYPE_LOCAL_REFERENCE:
 172 
 173         RefType = StackDesc->Reference.Class;
 174 
 175         switch (RefType)
 176         {
 177         case ACPI_REFCLASS_LOCAL:
 178         case ACPI_REFCLASS_ARG:
 179             /*
 180              * Get the local from the method's state info
 181              * Note: this increments the local's object reference count
 182              */
 183             Status = AcpiDsMethodDataGetValue (RefType,
 184                             StackDesc->Reference.Value, WalkState, &ObjDesc);
 185             if (ACPI_FAILURE (Status))
 186             {
 187                 return_ACPI_STATUS (Status);
 188             }
 189 
 190             ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "[Arg/Local %X] ValueObj is %p\n",
 191                 StackDesc->Reference.Value, ObjDesc));
 192 
 193             /*
 194              * Now we can delete the original Reference Object and
 195              * replace it with the resolved value
 196              */
 197             AcpiUtRemoveReference (StackDesc);
 198             *StackPtr = ObjDesc;
 199             break;
 200 
 201         case ACPI_REFCLASS_INDEX:
 202 
 203             switch (StackDesc->Reference.TargetType)
 204             {
 205             case ACPI_TYPE_BUFFER_FIELD:
 206 
 207                 /* Just return - do not dereference */
 208                 break;
 209 
 210             case ACPI_TYPE_PACKAGE:
 211 
 212                 /* If method call or CopyObject - do not dereference */
 213 
 214                 if ((WalkState->Opcode == AML_INT_METHODCALL_OP) ||
 215                     (WalkState->Opcode == AML_COPY_OP))
 216                 {
 217                     break;
 218                 }
 219 
 220                 /* Otherwise, dereference the PackageIndex to a package element */
 221 
 222                 ObjDesc = *StackDesc->Reference.Where;
 223                 if (ObjDesc)
 224                 {
 225                     /*
 226                      * Valid object descriptor, copy pointer to return value
 227                      * (i.e., dereference the package index)
 228                      * Delete the ref object, increment the returned object
 229                      */
 230                     AcpiUtRemoveReference (StackDesc);
 231                     AcpiUtAddReference (ObjDesc);
 232                     *StackPtr = ObjDesc;
 233                 }
 234                 else
 235                 {
 236                     /*
 237                      * A NULL object descriptor means an uninitialized element of
 238                      * the package, can't dereference it
 239                      */
 240                     ACPI_ERROR ((AE_INFO,
 241                         "Attempt to dereference an Index to NULL package element Idx=%p",
 242                         StackDesc));
 243                     Status = AE_AML_UNINITIALIZED_ELEMENT;
 244                 }
 245                 break;
 246 
 247             default:
 248 
 249                 /* Invalid reference object */
 250 
 251                 ACPI_ERROR ((AE_INFO,
 252                     "Unknown TargetType 0x%X in Index/Reference object %p",
 253                     StackDesc->Reference.TargetType, StackDesc));
 254                 Status = AE_AML_INTERNAL;
 255                 break;
 256             }
 257             break;
 258 
 259         case ACPI_REFCLASS_REFOF:
 260         case ACPI_REFCLASS_DEBUG:
 261         case ACPI_REFCLASS_TABLE:
 262 
 263             /* Just leave the object as-is, do not dereference */
 264 
 265             break;
 266 
 267         case ACPI_REFCLASS_NAME:   /* Reference to a named object */
 268 
 269             /* Dereference the name */
 270 
 271             if ((StackDesc->Reference.Node->Type == ACPI_TYPE_DEVICE) ||
 272                 (StackDesc->Reference.Node->Type == ACPI_TYPE_THERMAL))
 273             {
 274                 /* These node types do not have 'real' subobjects */
 275 
 276                 *StackPtr = (void *) StackDesc->Reference.Node;
 277             }
 278             else
 279             {
 280                 /* Get the object pointed to by the namespace node */
 281 
 282                 *StackPtr = (StackDesc->Reference.Node)->Object;
 283                 AcpiUtAddReference (*StackPtr);
 284             }
 285 
 286             AcpiUtRemoveReference (StackDesc);
 287             break;
 288 
 289         default:
 290 
 291             ACPI_ERROR ((AE_INFO,
 292                 "Unknown Reference type 0x%X in %p", RefType, StackDesc));
 293             Status = AE_AML_INTERNAL;
 294             break;
 295         }
 296         break;
 297 
 298     case ACPI_TYPE_BUFFER:
 299 
 300         Status = AcpiDsGetBufferArguments (StackDesc);
 301         break;
 302 
 303     case ACPI_TYPE_PACKAGE:
 304 
 305         Status = AcpiDsGetPackageArguments (StackDesc);
 306         break;
 307 
 308     case ACPI_TYPE_BUFFER_FIELD:
 309     case ACPI_TYPE_LOCAL_REGION_FIELD:
 310     case ACPI_TYPE_LOCAL_BANK_FIELD:
 311     case ACPI_TYPE_LOCAL_INDEX_FIELD:
 312 
 313         ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "FieldRead SourceDesc=%p Type=%X\n",
 314             StackDesc, StackDesc->Common.Type));
 315 
 316         Status = AcpiExReadDataFromField (WalkState, StackDesc, &ObjDesc);
 317 
 318         /* Remove a reference to the original operand, then override */
 319 
 320         AcpiUtRemoveReference (*StackPtr);
 321         *StackPtr = (void *) ObjDesc;
 322         break;
 323 
 324     default:
 325 
 326         break;
 327     }
 328 
 329     return_ACPI_STATUS (Status);
 330 }
 331 
 332 
 333 /*******************************************************************************
 334  *
 335  * FUNCTION:    AcpiExResolveMultiple
 336  *
 337  * PARAMETERS:  WalkState           - Current state (contains AML opcode)
 338  *              Operand             - Starting point for resolution
 339  *              ReturnType          - Where the object type is returned
 340  *              ReturnDesc          - Where the resolved object is returned
 341  *
 342  * RETURN:      Status
 343  *
 344  * DESCRIPTION: Return the base object and type. Traverse a reference list if
 345  *              necessary to get to the base object.
 346  *
 347  ******************************************************************************/
 348 
 349 ACPI_STATUS
 350 AcpiExResolveMultiple (
 351     ACPI_WALK_STATE         *WalkState,
 352     ACPI_OPERAND_OBJECT     *Operand,
 353     ACPI_OBJECT_TYPE        *ReturnType,
 354     ACPI_OPERAND_OBJECT     **ReturnDesc)
 355 {
 356     ACPI_OPERAND_OBJECT     *ObjDesc = (void *) Operand;
 357     ACPI_NAMESPACE_NODE     *Node;
 358     ACPI_OBJECT_TYPE        Type;
 359     ACPI_STATUS             Status;
 360 
 361 
 362     ACPI_FUNCTION_TRACE (AcpiExResolveMultiple);
 363 
 364 
 365     /* Operand can be either a namespace node or an operand descriptor */
 366 
 367     switch (ACPI_GET_DESCRIPTOR_TYPE (ObjDesc))
 368     {
 369     case ACPI_DESC_TYPE_OPERAND:
 370 
 371         Type = ObjDesc->Common.Type;
 372         break;
 373 
 374     case ACPI_DESC_TYPE_NAMED:
 375 
 376         Type = ((ACPI_NAMESPACE_NODE *) ObjDesc)->Type;
 377         ObjDesc = AcpiNsGetAttachedObject ((ACPI_NAMESPACE_NODE *) ObjDesc);
 378 
 379         /* If we had an Alias node, use the attached object for type info */
 380 
 381         if (Type == ACPI_TYPE_LOCAL_ALIAS)
 382         {
 383             Type = ((ACPI_NAMESPACE_NODE *) ObjDesc)->Type;
 384             ObjDesc = AcpiNsGetAttachedObject ((ACPI_NAMESPACE_NODE *) ObjDesc);
 385         }
 386         break;
 387 
 388     default:
 389         return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
 390     }
 391 
 392     /* If type is anything other than a reference, we are done */
 393 
 394     if (Type != ACPI_TYPE_LOCAL_REFERENCE)
 395     {
 396         goto Exit;
 397     }
 398 
 399     /*
 400      * For reference objects created via the RefOf, Index, or Load/LoadTable
 401      * operators, we need to get to the base object (as per the ACPI
 402      * specification of the ObjectType and SizeOf operators). This means
 403      * traversing the list of possibly many nested references.
 404      */
 405     while (ObjDesc->Common.Type == ACPI_TYPE_LOCAL_REFERENCE)
 406     {
 407         switch (ObjDesc->Reference.Class)
 408         {
 409         case ACPI_REFCLASS_REFOF:
 410         case ACPI_REFCLASS_NAME:
 411 
 412             /* Dereference the reference pointer */
 413 
 414             if (ObjDesc->Reference.Class == ACPI_REFCLASS_REFOF)
 415             {
 416                 Node = ObjDesc->Reference.Object;
 417             }
 418             else /* AML_INT_NAMEPATH_OP */
 419             {
 420                 Node = ObjDesc->Reference.Node;
 421             }
 422 
 423             /* All "References" point to a NS node */
 424 
 425             if (ACPI_GET_DESCRIPTOR_TYPE (Node) != ACPI_DESC_TYPE_NAMED)
 426             {
 427                 ACPI_ERROR ((AE_INFO,
 428                     "Not a namespace node %p [%s]",
 429                     Node, AcpiUtGetDescriptorName (Node)));
 430                 return_ACPI_STATUS (AE_AML_INTERNAL);
 431             }
 432 
 433             /* Get the attached object */
 434 
 435             ObjDesc = AcpiNsGetAttachedObject (Node);
 436             if (!ObjDesc)
 437             {
 438                 /* No object, use the NS node type */
 439 
 440                 Type = AcpiNsGetType (Node);
 441                 goto Exit;
 442             }
 443 
 444             /* Check for circular references */
 445 
 446             if (ObjDesc == Operand)
 447             {
 448                 return_ACPI_STATUS (AE_AML_CIRCULAR_REFERENCE);
 449             }
 450             break;
 451 
 452         case ACPI_REFCLASS_INDEX:
 453 
 454             /* Get the type of this reference (index into another object) */
 455 
 456             Type = ObjDesc->Reference.TargetType;
 457             if (Type != ACPI_TYPE_PACKAGE)
 458             {
 459                 goto Exit;
 460             }
 461 
 462             /*
 463              * The main object is a package, we want to get the type
 464              * of the individual package element that is referenced by
 465              * the index.
 466              *
 467              * This could of course in turn be another reference object.
 468              */
 469             ObjDesc = *(ObjDesc->Reference.Where);
 470             if (!ObjDesc)
 471             {
 472                 /* NULL package elements are allowed */
 473 
 474                 Type = 0; /* Uninitialized */
 475                 goto Exit;
 476             }
 477             break;
 478 
 479         case ACPI_REFCLASS_TABLE:
 480 
 481             Type = ACPI_TYPE_DDB_HANDLE;
 482             goto Exit;
 483 
 484         case ACPI_REFCLASS_LOCAL:
 485         case ACPI_REFCLASS_ARG:
 486 
 487             if (ReturnDesc)
 488             {
 489                 Status = AcpiDsMethodDataGetValue (ObjDesc->Reference.Class,
 490                             ObjDesc->Reference.Value, WalkState, &ObjDesc);
 491                 if (ACPI_FAILURE (Status))
 492                 {
 493                     return_ACPI_STATUS (Status);
 494                 }
 495                 AcpiUtRemoveReference (ObjDesc);
 496             }
 497             else
 498             {
 499                 Status = AcpiDsMethodDataGetNode (ObjDesc->Reference.Class,
 500                             ObjDesc->Reference.Value, WalkState, &Node);
 501                 if (ACPI_FAILURE (Status))
 502                 {
 503                     return_ACPI_STATUS (Status);
 504                 }
 505 
 506                 ObjDesc = AcpiNsGetAttachedObject (Node);
 507                 if (!ObjDesc)
 508                 {
 509                     Type = ACPI_TYPE_ANY;
 510                     goto Exit;
 511                 }
 512             }
 513             break;
 514 
 515         case ACPI_REFCLASS_DEBUG:
 516 
 517             /* The Debug Object is of type "DebugObject" */
 518 
 519             Type = ACPI_TYPE_DEBUG_OBJECT;
 520             goto Exit;
 521 
 522         default:
 523 
 524             ACPI_ERROR ((AE_INFO,
 525                 "Unknown Reference Class 0x%2.2X", ObjDesc->Reference.Class));
 526             return_ACPI_STATUS (AE_AML_INTERNAL);
 527         }
 528     }
 529 
 530     /*
 531      * Now we are guaranteed to have an object that has not been created
 532      * via the RefOf or Index operators.
 533      */
 534     Type = ObjDesc->Common.Type;
 535 
 536 
 537 Exit:
 538     /* Convert internal types to external types */
 539 
 540     switch (Type)
 541     {
 542     case ACPI_TYPE_LOCAL_REGION_FIELD:
 543     case ACPI_TYPE_LOCAL_BANK_FIELD:
 544     case ACPI_TYPE_LOCAL_INDEX_FIELD:
 545 
 546         Type = ACPI_TYPE_FIELD_UNIT;
 547         break;
 548 
 549     case ACPI_TYPE_LOCAL_SCOPE:
 550 
 551         /* Per ACPI Specification, Scope is untyped */
 552 
 553         Type = ACPI_TYPE_ANY;
 554         break;
 555 
 556     default:
 557 
 558         /* No change to Type required */
 559 
 560         break;
 561     }
 562 
 563     *ReturnType = Type;
 564     if (ReturnDesc)
 565     {
 566         *ReturnDesc = ObjDesc;
 567     }
 568     return_ACPI_STATUS (AE_OK);
 569 }