1 /******************************************************************************
3 * Module Name: dspkginit - Completion of deferred package initialization
5 *****************************************************************************/
8 * Copyright (C) 2000 - 2017, Intel Corp.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
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.
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.
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.
52 #define _COMPONENT ACPI_NAMESPACE
53 ACPI_MODULE_NAME ("dspkginit")
56 /* Local prototypes */
59 AcpiDsResolvePackageElement (
60 ACPI_OPERAND_OBJECT
**Element
);
63 /*******************************************************************************
65 * FUNCTION: AcpiDsBuildInternalPackageObj
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
75 * DESCRIPTION: Translate a parser Op package object to the equivalent
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.)
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.
90 ******************************************************************************/
93 AcpiDsBuildInternalPackageObj (
94 ACPI_WALK_STATE
*WalkState
,
95 ACPI_PARSE_OBJECT
*Op
,
97 ACPI_OPERAND_OBJECT
**ObjDescPtr
)
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
;
108 ACPI_FUNCTION_TRACE (DsBuildInternalPackageObj
);
111 /* Find the parent of a possibly nested package */
113 Parent
= Op
->Common
.Parent
;
114 while ((Parent
->Common
.AmlOpcode
== AML_PACKAGE_OP
) ||
115 (Parent
->Common
.AmlOpcode
== AML_VARIABLE_PACKAGE_OP
))
117 Parent
= Parent
->Common
.Parent
;
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.
125 ObjDesc
= *ObjDescPtr
;
128 ObjDesc
= AcpiUtCreateInternalObject (ACPI_TYPE_PACKAGE
);
129 *ObjDescPtr
= ObjDesc
;
132 return_ACPI_STATUS (AE_NO_MEMORY
);
135 ObjDesc
->Package
.Node
= Parent
->Common
.Node
;
138 if (ObjDesc
->Package
.Flags
& AOPOBJ_DATA_VALID
) /* Just in case */
140 return_ACPI_STATUS (AE_OK
);
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.
148 ObjDesc
->Package
.Elements
= ACPI_ALLOCATE_ZEROED (
149 ((ACPI_SIZE
) ElementCount
+ 1) * sizeof (void *));
151 if (!ObjDesc
->Package
.Elements
)
153 AcpiUtDeleteObjectDesc (ObjDesc
);
154 return_ACPI_STATUS (AE_NO_MEMORY
);
157 ObjDesc
->Package
.Count
= ElementCount
;
158 Arg
= Op
->Common
.Value
.Arg
;
159 Arg
= Arg
->Common
.Next
;
163 ObjDesc
->Package
.Flags
|= AOPOBJ_DATA_VALID
;
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.
172 for (i
= 0; Arg
&& (i
< ElementCount
); i
++)
174 if (Arg
->Common
.AmlOpcode
== AML_INT_RETURN_VALUE_OP
)
176 if (Arg
->Common
.Node
->Type
== ACPI_TYPE_METHOD
)
179 * A method reference "looks" to the parser to be a method
180 * invocation, so we special case it here
182 Arg
->Common
.AmlOpcode
= AML_INT_NAMEPATH_OP
;
183 Status
= AcpiDsBuildInternalObject (
184 WalkState
, Arg
, &ObjDesc
->Package
.Elements
[i
]);
188 /* This package element is already built, just get it */
190 ObjDesc
->Package
.Elements
[i
] =
191 ACPI_CAST_PTR (ACPI_OPERAND_OBJECT
, Arg
->Common
.Node
);
196 Status
= AcpiDsBuildInternalObject (
197 WalkState
, Arg
, &ObjDesc
->Package
.Elements
[i
]);
198 if (Status
== AE_NOT_FOUND
)
200 ACPI_ERROR ((AE_INFO
, "%-48s", "****DS namepath not found"));
204 * Initialize this package element. This function handles the
205 * resolution of named references within the package.
207 AcpiDsInitPackageElement (0, ObjDesc
->Package
.Elements
[i
],
208 NULL
, &ObjDesc
->Package
.Elements
[i
]);
213 /* Existing package, get existing reference count */
215 ReferenceCount
= (*ObjDescPtr
)->Common
.ReferenceCount
;
216 if (ReferenceCount
> 1)
218 /* Make new element ref count match original ref count */
219 /* TBD: Probably need an AcpiUtAddReferences function */
221 for (Index
= 0; Index
< ((UINT32
) ReferenceCount
- 1); Index
++)
223 AcpiUtAddReference ((ObjDesc
->Package
.Elements
[i
]));
228 Arg
= Arg
->Common
.Next
;
231 /* Check for match between NumElements and actual length of PackageList */
236 * NumElements was exhausted, but there are remaining elements in
237 * the PackageList. Truncate the package to NumElements.
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.
250 * We must delete any package elements that were created earlier
251 * and are not going to be used because of the package truncation.
253 if (Arg
->Common
.Node
)
255 AcpiUtRemoveReference (
256 ACPI_CAST_PTR (ACPI_OPERAND_OBJECT
, Arg
->Common
.Node
));
257 Arg
->Common
.Node
= NULL
;
260 /* Find out how many elements there really are */
263 Arg
= Arg
->Common
.Next
;
267 "Actual Package length (%u) is larger than "
268 "NumElements field (%u), truncated",
271 else if (i
< ElementCount
)
274 * Arg list (elements) was exhausted, but we did not reach
277 * Note: this is not an error, the package is padded out
280 ACPI_DEBUG_PRINT ((ACPI_DB_INFO
,
281 "Package List length (%u) smaller than NumElements "
282 "count (%u), padded with null elements\n",
286 ObjDesc
->Package
.Flags
|= AOPOBJ_DATA_VALID
;
287 Op
->Common
.Node
= ACPI_CAST_PTR (ACPI_NAMESPACE_NODE
, ObjDesc
);
288 return_ACPI_STATUS (Status
);
292 /*******************************************************************************
294 * FUNCTION: AcpiDsInitPackageElement
296 * PARAMETERS: ACPI_PKG_CALLBACK
300 * DESCRIPTION: Resolve a named reference element within a package object
302 ******************************************************************************/
305 AcpiDsInitPackageElement (
307 ACPI_OPERAND_OBJECT
*SourceObject
,
308 ACPI_GENERIC_STATE
*State
,
311 ACPI_OPERAND_OBJECT
**ElementPtr
;
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.
327 /* A direct call was made to this function */
329 ElementPtr
= (ACPI_OPERAND_OBJECT
**) Context
;
333 /* Call came from AcpiUtWalkPackageTree */
335 ElementPtr
= State
->Pkg
.ThisTargetObj
;
338 /* We are only interested in reference objects/elements */
340 if (SourceObject
->Common
.Type
== ACPI_TYPE_LOCAL_REFERENCE
)
342 /* Attempt to resolve the (named) reference to a namespace node */
344 AcpiDsResolvePackageElement (ElementPtr
);
346 else if (SourceObject
->Common
.Type
== ACPI_TYPE_PACKAGE
)
348 SourceObject
->Package
.Flags
|= AOPOBJ_DATA_VALID
;
355 /*******************************************************************************
357 * FUNCTION: AcpiDsResolvePackageElement
359 * PARAMETERS: ElementPtr - Pointer to a reference object
361 * RETURN: Possible new element is stored to the indirect ElementPtr
363 * DESCRIPTION: Resolve a package element that is a reference to a named
366 ******************************************************************************/
369 AcpiDsResolvePackageElement (
370 ACPI_OPERAND_OBJECT
**ElementPtr
)
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
;
380 ACPI_FUNCTION_TRACE (DsResolvePackageElement
);
383 /* Check if reference element is already resolved */
385 if (Element
->Reference
.Resolved
)
390 /* Element must be a reference object of correct type */
392 ScopeInfo
.Scope
.Node
= Element
->Reference
.Node
; /* Prefix node */
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
))
401 Status
= AcpiNsExternalizeName (ACPI_UINT32_MAX
,
402 (char *) Element
->Reference
.Aml
,
403 NULL
, &ExternalPath
);
405 ACPI_EXCEPTION ((AE_INFO
, Status
,
406 "Could not find/resolve named package element: %s", ExternalPath
));
408 ACPI_FREE (ExternalPath
);
412 else if (ResolvedNode
->Type
== ACPI_TYPE_ANY
)
414 /* Named reference not resolved, return a NULL package element */
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
));
423 else if (ResolvedNode
->Flags
& ANOBJ_TEMPORARY
)
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).
432 ACPI_ERROR ((AE_INFO
,
433 "Package element refers to a temporary name [%4.4s], "
434 "inserting a NULL element",
435 ResolvedNode
->Name
.Ascii
));
442 * Special handling for Alias objects. We need ResolvedNode to point
443 * to the Alias target. This effectively "resolves" the alias.
445 if (ResolvedNode
->Type
== ACPI_TYPE_LOCAL_ALIAS
)
447 ResolvedNode
= ACPI_CAST_PTR (ACPI_NAMESPACE_NODE
,
448 ResolvedNode
->Object
);
451 /* Update the reference object */
453 Element
->Reference
.Resolved
= TRUE
;
454 Element
->Reference
.Node
= ResolvedNode
;
455 Type
= Element
->Reference
.Node
->Type
;
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).
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.
471 Status
= AcpiExResolveNodeToValue (&ResolvedNode
, NULL
);
472 if (ACPI_FAILURE (Status
))
478 /* TBD - alias support */
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.
484 Type
= Op
->Common
.Node
->Type
;
485 if (Type
== ACPI_TYPE_LOCAL_ALIAS
)
487 Type
= ObjDesc
->Common
.Type
;
488 Op
->Common
.Node
= ACPI_CAST_PTR (ACPI_NAMESPACE_NODE
,
489 Op
->Common
.Node
->Object
);
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".
500 case ACPI_TYPE_DEVICE
:
501 case ACPI_TYPE_THERMAL
:
503 /* TBD: This may not be necesssary */
505 AcpiUtAddReference (ResolvedNode
->Object
);
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
:
519 * For all other types - the node was resolved to an actual
520 * operand object with a value, return the object
522 *ElementPtr
= (ACPI_OPERAND_OBJECT
*) ResolvedNode
;