Home | History | Annotate | Line # | Download | only in dispatcher
dspkginit.c revision 1.1
      1 /******************************************************************************
      2  *
      3  * Module Name: dspkginit - Completion of deferred package initialization
      4  *
      5  *****************************************************************************/
      6 
      7 /*
      8  * Copyright (C) 2000 - 2017, 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 #include "acpi.h"
     45 #include "accommon.h"
     46 #include "acnamesp.h"
     47 #include "amlcode.h"
     48 #include "acdispat.h"
     49 #include "acinterp.h"
     50 
     51 
     52 #define _COMPONENT          ACPI_NAMESPACE
     53         ACPI_MODULE_NAME    ("dspkginit")
     54 
     55 
     56 /* Local prototypes */
     57 
     58 static void
     59 AcpiDsResolvePackageElement (
     60     ACPI_OPERAND_OBJECT     **Element);
     61 
     62 
     63 /*******************************************************************************
     64  *
     65  * FUNCTION:    AcpiDsBuildInternalPackageObj
     66  *
     67  * PARAMETERS:  WalkState       - Current walk state
     68  *              Op              - Parser object to be translated
     69  *              ElementCount    - Number of elements in the package - this is
     70  *                                the NumElements argument to Package()
     71  *              ObjDescPtr      - Where the ACPI internal object is returned
     72  *
     73  * RETURN:      Status
     74  *
     75  * DESCRIPTION: Translate a parser Op package object to the equivalent
     76  *              namespace object
     77  *
     78  * NOTE: The number of elements in the package will be always be the NumElements
     79  * count, regardless of the number of elements in the package list. If
     80  * NumElements is smaller, only that many package list elements are used.
     81  * if NumElements is larger, the Package object is padded out with
     82  * objects of type Uninitialized (as per ACPI spec.)
     83  *
     84  * Even though the ASL compilers do not allow NumElements to be smaller
     85  * than the Package list length (for the fixed length package opcode), some
     86  * BIOS code modifies the AML on the fly to adjust the NumElements, and
     87  * this code compensates for that. This also provides compatibility with
     88  * other AML interpreters.
     89  *
     90  ******************************************************************************/
     91 
     92 ACPI_STATUS
     93 AcpiDsBuildInternalPackageObj (
     94     ACPI_WALK_STATE         *WalkState,
     95     ACPI_PARSE_OBJECT       *Op,
     96     UINT32                  ElementCount,
     97     ACPI_OPERAND_OBJECT     **ObjDescPtr)
     98 {
     99     ACPI_PARSE_OBJECT       *Arg;
    100     ACPI_PARSE_OBJECT       *Parent;
    101     ACPI_OPERAND_OBJECT     *ObjDesc = NULL;
    102     ACPI_STATUS             Status = AE_OK;
    103     UINT16                  ReferenceCount;
    104     UINT32                  Index;
    105     UINT32                  i;
    106 
    107 
    108     ACPI_FUNCTION_TRACE (DsBuildInternalPackageObj);
    109 
    110 
    111     /* Find the parent of a possibly nested package */
    112 
    113     Parent = Op->Common.Parent;
    114     while ((Parent->Common.AmlOpcode == AML_PACKAGE_OP) ||
    115            (Parent->Common.AmlOpcode == AML_VARIABLE_PACKAGE_OP))
    116     {
    117         Parent = Parent->Common.Parent;
    118     }
    119 
    120     /*
    121      * If we are evaluating a Named package object of the form:
    122      *      Name (xxxx, Package)
    123      * the package object already exists, otherwise it must be created.
    124      */
    125     ObjDesc = *ObjDescPtr;
    126     if (!ObjDesc)
    127     {
    128         ObjDesc = AcpiUtCreateInternalObject (ACPI_TYPE_PACKAGE);
    129         *ObjDescPtr = ObjDesc;
    130         if (!ObjDesc)
    131         {
    132             return_ACPI_STATUS (AE_NO_MEMORY);
    133         }
    134 
    135         ObjDesc->Package.Node = Parent->Common.Node;
    136     }
    137 
    138     if (ObjDesc->Package.Flags & AOPOBJ_DATA_VALID) /* Just in case */
    139     {
    140         return_ACPI_STATUS (AE_OK);
    141     }
    142 
    143     /*
    144      * Allocate the element array (array of pointers to the individual
    145      * objects) based on the NumElements parameter. Add an extra pointer slot
    146      * so that the list is always null terminated.
    147      */
    148     ObjDesc->Package.Elements = ACPI_ALLOCATE_ZEROED (
    149         ((ACPI_SIZE) ElementCount + 1) * sizeof (void *));
    150 
    151     if (!ObjDesc->Package.Elements)
    152     {
    153         AcpiUtDeleteObjectDesc (ObjDesc);
    154         return_ACPI_STATUS (AE_NO_MEMORY);
    155     }
    156 
    157     ObjDesc->Package.Count = ElementCount;
    158     Arg = Op->Common.Value.Arg;
    159     Arg = Arg->Common.Next;
    160 
    161     if (Arg)
    162     {
    163         ObjDesc->Package.Flags |= AOPOBJ_DATA_VALID;
    164     }
    165 
    166     /*
    167      * Initialize the elements of the package, up to the NumElements count.
    168      * Package is automatically padded with uninitialized (NULL) elements
    169      * if NumElements is greater than the package list length. Likewise,
    170      * Package is truncated if NumElements is less than the list length.
    171      */
    172     for (i = 0; Arg && (i < ElementCount); i++)
    173     {
    174         if (Arg->Common.AmlOpcode == AML_INT_RETURN_VALUE_OP)
    175         {
    176             if (Arg->Common.Node->Type == ACPI_TYPE_METHOD)
    177             {
    178                 /*
    179                  * A method reference "looks" to the parser to be a method
    180                  * invocation, so we special case it here
    181                  */
    182                 Arg->Common.AmlOpcode = AML_INT_NAMEPATH_OP;
    183                 Status = AcpiDsBuildInternalObject (
    184                     WalkState, Arg, &ObjDesc->Package.Elements[i]);
    185             }
    186             else
    187             {
    188                 /* This package element is already built, just get it */
    189 
    190                 ObjDesc->Package.Elements[i] =
    191                     ACPI_CAST_PTR (ACPI_OPERAND_OBJECT, Arg->Common.Node);
    192             }
    193         }
    194         else
    195         {
    196             Status = AcpiDsBuildInternalObject (
    197                 WalkState, Arg, &ObjDesc->Package.Elements[i]);
    198             if (Status == AE_NOT_FOUND)
    199             {
    200                 ACPI_ERROR ((AE_INFO, "%-48s", "****DS namepath not found"));
    201             }
    202 
    203             /*
    204              * Initialize this package element. This function handles the
    205              * resolution of named references within the package.
    206              */
    207             AcpiDsInitPackageElement (0, ObjDesc->Package.Elements[i],
    208                 NULL, &ObjDesc->Package.Elements[i]);
    209         }
    210 
    211         if (*ObjDescPtr)
    212         {
    213             /* Existing package, get existing reference count */
    214 
    215             ReferenceCount = (*ObjDescPtr)->Common.ReferenceCount;
    216             if (ReferenceCount > 1)
    217             {
    218                 /* Make new element ref count match original ref count */
    219                 /* TBD: Probably need an AcpiUtAddReferences function */
    220 
    221                 for (Index = 0; Index < ((UINT32) ReferenceCount - 1); Index++)
    222                 {
    223                     AcpiUtAddReference ((ObjDesc->Package.Elements[i]));
    224                 }
    225             }
    226         }
    227 
    228         Arg = Arg->Common.Next;
    229     }
    230 
    231     /* Check for match between NumElements and actual length of PackageList */
    232 
    233     if (Arg)
    234     {
    235         /*
    236          * NumElements was exhausted, but there are remaining elements in
    237          * the PackageList. Truncate the package to NumElements.
    238          *
    239          * Note: technically, this is an error, from ACPI spec: "It is an
    240          * error for NumElements to be less than the number of elements in
    241          * the PackageList". However, we just print a message and no
    242          * exception is returned. This provides compatibility with other
    243          * ACPI implementations. Some firmware implementations will alter
    244          * the NumElements on the fly, possibly creating this type of
    245          * ill-formed package object.
    246          */
    247         while (Arg)
    248         {
    249             /*
    250              * We must delete any package elements that were created earlier
    251              * and are not going to be used because of the package truncation.
    252              */
    253             if (Arg->Common.Node)
    254             {
    255                 AcpiUtRemoveReference (
    256                     ACPI_CAST_PTR (ACPI_OPERAND_OBJECT, Arg->Common.Node));
    257                 Arg->Common.Node = NULL;
    258             }
    259 
    260             /* Find out how many elements there really are */
    261 
    262             i++;
    263             Arg = Arg->Common.Next;
    264         }
    265 
    266         ACPI_INFO ((
    267             "Actual Package length (%u) is larger than "
    268             "NumElements field (%u), truncated",
    269             i, ElementCount));
    270     }
    271     else if (i < ElementCount)
    272     {
    273         /*
    274          * Arg list (elements) was exhausted, but we did not reach
    275          * NumElements count.
    276          *
    277          * Note: this is not an error, the package is padded out
    278          * with NULLs.
    279          */
    280         ACPI_DEBUG_PRINT ((ACPI_DB_INFO,
    281             "Package List length (%u) smaller than NumElements "
    282             "count (%u), padded with null elements\n",
    283             i, ElementCount));
    284     }
    285 
    286     ObjDesc->Package.Flags |= AOPOBJ_DATA_VALID;
    287     Op->Common.Node = ACPI_CAST_PTR (ACPI_NAMESPACE_NODE, ObjDesc);
    288     return_ACPI_STATUS (Status);
    289 }
    290 
    291 
    292 /*******************************************************************************
    293  *
    294  * FUNCTION:    AcpiDsInitPackageElement
    295  *
    296  * PARAMETERS:  ACPI_PKG_CALLBACK
    297  *
    298  * RETURN:      Status
    299  *
    300  * DESCRIPTION: Resolve a named reference element within a package object
    301  *
    302  ******************************************************************************/
    303 
    304 ACPI_STATUS
    305 AcpiDsInitPackageElement (
    306     UINT8                   ObjectType,
    307     ACPI_OPERAND_OBJECT     *SourceObject,
    308     ACPI_GENERIC_STATE      *State,
    309     void                    *Context)
    310 {
    311     ACPI_OPERAND_OBJECT     **ElementPtr;
    312 
    313 
    314     if (!SourceObject)
    315     {
    316         return (AE_OK);
    317     }
    318 
    319     /*
    320      * The following code is a bit of a hack to workaround a (current)
    321      * limitation of the ACPI_PKG_CALLBACK interface. We need a pointer
    322      * to the location within the element array because a new object
    323      * may be created and stored there.
    324      */
    325     if (Context)
    326     {
    327         /* A direct call was made to this function */
    328 
    329         ElementPtr = (ACPI_OPERAND_OBJECT **) Context;
    330     }
    331     else
    332     {
    333         /* Call came from AcpiUtWalkPackageTree */
    334 
    335         ElementPtr = State->Pkg.ThisTargetObj;
    336     }
    337 
    338     /* We are only interested in reference objects/elements */
    339 
    340     if (SourceObject->Common.Type == ACPI_TYPE_LOCAL_REFERENCE)
    341     {
    342         /* Attempt to resolve the (named) reference to a namespace node */
    343 
    344         AcpiDsResolvePackageElement (ElementPtr);
    345     }
    346     else if (SourceObject->Common.Type == ACPI_TYPE_PACKAGE)
    347     {
    348         SourceObject->Package.Flags |= AOPOBJ_DATA_VALID;
    349     }
    350 
    351     return (AE_OK);
    352 }
    353 
    354 
    355 /*******************************************************************************
    356  *
    357  * FUNCTION:    AcpiDsResolvePackageElement
    358  *
    359  * PARAMETERS:  ElementPtr          - Pointer to a reference object
    360  *
    361  * RETURN:      Possible new element is stored to the indirect ElementPtr
    362  *
    363  * DESCRIPTION: Resolve a package element that is a reference to a named
    364  *              object.
    365  *
    366  ******************************************************************************/
    367 
    368 static void
    369 AcpiDsResolvePackageElement (
    370     ACPI_OPERAND_OBJECT     **ElementPtr)
    371 {
    372     ACPI_STATUS             Status;
    373     ACPI_GENERIC_STATE      ScopeInfo;
    374     ACPI_OPERAND_OBJECT     *Element = *ElementPtr;
    375     ACPI_NAMESPACE_NODE     *ResolvedNode;
    376     char                    *ExternalPath = NULL;
    377     ACPI_OBJECT_TYPE        Type;
    378 
    379 
    380     ACPI_FUNCTION_TRACE (DsResolvePackageElement);
    381 
    382 
    383     /* Check if reference element is already resolved */
    384 
    385     if (Element->Reference.Resolved)
    386     {
    387         return_VOID;
    388     }
    389 
    390     /* Element must be a reference object of correct type */
    391 
    392     ScopeInfo.Scope.Node = Element->Reference.Node; /* Prefix node */
    393 
    394     Status = AcpiNsLookup (&ScopeInfo,
    395         (char *) Element->Reference.Aml,            /* Pointer to AML path */
    396         ACPI_TYPE_ANY, ACPI_IMODE_EXECUTE,
    397         ACPI_NS_SEARCH_PARENT | ACPI_NS_DONT_OPEN_SCOPE,
    398         NULL, &ResolvedNode);
    399     if (ACPI_FAILURE (Status))
    400     {
    401         Status = AcpiNsExternalizeName (ACPI_UINT32_MAX,
    402             (char *) Element->Reference.Aml,
    403             NULL, &ExternalPath);
    404 
    405         ACPI_EXCEPTION ((AE_INFO, Status,
    406             "Could not find/resolve named package element: %s", ExternalPath));
    407 
    408         ACPI_FREE (ExternalPath);
    409         *ElementPtr = NULL;
    410         return_VOID;
    411     }
    412     else if (ResolvedNode->Type == ACPI_TYPE_ANY)
    413     {
    414         /* Named reference not resolved, return a NULL package element */
    415 
    416         ACPI_ERROR ((AE_INFO,
    417             "Could not resolve named package element [%4.4s] in [%4.4s]",
    418             ResolvedNode->Name.Ascii, ScopeInfo.Scope.Node->Name.Ascii));
    419         *ElementPtr = NULL;
    420         return_VOID;
    421     }
    422 #if 0
    423     else if (ResolvedNode->Flags & ANOBJ_TEMPORARY)
    424     {
    425         /*
    426          * A temporary node found here indicates that the reference is
    427          * to a node that was created within this method. We are not
    428          * going to allow it (especially if the package is returned
    429          * from the method) -- the temporary node will be deleted out
    430          * from under the method. (05/2017).
    431          */
    432         ACPI_ERROR ((AE_INFO,
    433             "Package element refers to a temporary name [%4.4s], "
    434             "inserting a NULL element",
    435             ResolvedNode->Name.Ascii));
    436         *ElementPtr = NULL;
    437         return_VOID;
    438     }
    439 #endif
    440 
    441     /*
    442      * Special handling for Alias objects. We need ResolvedNode to point
    443      * to the Alias target. This effectively "resolves" the alias.
    444      */
    445     if (ResolvedNode->Type == ACPI_TYPE_LOCAL_ALIAS)
    446     {
    447         ResolvedNode = ACPI_CAST_PTR (ACPI_NAMESPACE_NODE,
    448             ResolvedNode->Object);
    449     }
    450 
    451     /* Update the reference object */
    452 
    453     Element->Reference.Resolved = TRUE;
    454     Element->Reference.Node = ResolvedNode;
    455     Type = Element->Reference.Node->Type;
    456 
    457     /*
    458      * Attempt to resolve the node to a value before we insert it into
    459      * the package. If this is a reference to a common data type,
    460      * resolve it immediately. According to the ACPI spec, package
    461      * elements can only be "data objects" or method references.
    462      * Attempt to resolve to an Integer, Buffer, String or Package.
    463      * If cannot, return the named reference (for things like Devices,
    464      * Methods, etc.) Buffer Fields and Fields will resolve to simple
    465      * objects (int/buf/str/pkg).
    466      *
    467      * NOTE: References to things like Devices, Methods, Mutexes, etc.
    468      * will remain as named references. This behavior is not described
    469      * in the ACPI spec, but it appears to be an oversight.
    470      */
    471     Status = AcpiExResolveNodeToValue (&ResolvedNode, NULL);
    472     if (ACPI_FAILURE (Status))
    473     {
    474         return_VOID;
    475     }
    476 
    477 #if 0
    478 /* TBD - alias support */
    479     /*
    480      * Special handling for Alias objects. We need to setup the type
    481      * and the Op->Common.Node to point to the Alias target. Note,
    482      * Alias has at most one level of indirection internally.
    483      */
    484     Type = Op->Common.Node->Type;
    485     if (Type == ACPI_TYPE_LOCAL_ALIAS)
    486     {
    487         Type = ObjDesc->Common.Type;
    488         Op->Common.Node = ACPI_CAST_PTR (ACPI_NAMESPACE_NODE,
    489             Op->Common.Node->Object);
    490     }
    491 #endif
    492 
    493     switch (Type)
    494     {
    495     /*
    496      * These object types are a result of named references, so we will
    497      * leave them as reference objects. In other words, these types
    498      * have no intrinsic "value".
    499      */
    500     case ACPI_TYPE_DEVICE:
    501     case ACPI_TYPE_THERMAL:
    502 
    503         /* TBD: This may not be necesssary */
    504 
    505         AcpiUtAddReference (ResolvedNode->Object);
    506         break;
    507 
    508     case ACPI_TYPE_MUTEX:
    509     case ACPI_TYPE_METHOD:
    510     case ACPI_TYPE_POWER:
    511     case ACPI_TYPE_PROCESSOR:
    512     case ACPI_TYPE_EVENT:
    513     case ACPI_TYPE_REGION:
    514 
    515         break;
    516 
    517     default:
    518         /*
    519          * For all other types - the node was resolved to an actual
    520          * operand object with a value, return the object
    521          */
    522         *ElementPtr = (ACPI_OPERAND_OBJECT *) ResolvedNode;
    523         break;
    524     }
    525 
    526     return_VOID;
    527 }
    528