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