xref: /netbsd-src/sys/external/bsd/acpica/dist/dispatcher/dspkginit.c (revision 796c32c94f6e154afc9de0f63da35c91bb739b45)
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