xref: /freebsd/sys/contrib/dev/acpica/components/executer/exresolv.c (revision ddd5b8e9b4d8957fce018c520657cdfa4ecffad3)
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 <contrib/dev/acpica/include/acpi.h>
47 #include <contrib/dev/acpica/include/accommon.h>
48 #include <contrib/dev/acpica/include/amlcode.h>
49 #include <contrib/dev/acpica/include/acdispat.h>
50 #include <contrib/dev/acpica/include/acinterp.h>
51 #include <contrib/dev/acpica/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             /*
181              * Get the local from the method's state info
182              * Note: this increments the local's object reference count
183              */
184             Status = AcpiDsMethodDataGetValue (RefType,
185                             StackDesc->Reference.Value, WalkState, &ObjDesc);
186             if (ACPI_FAILURE (Status))
187             {
188                 return_ACPI_STATUS (Status);
189             }
190 
191             ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "[Arg/Local %X] ValueObj is %p\n",
192                 StackDesc->Reference.Value, ObjDesc));
193 
194             /*
195              * Now we can delete the original Reference Object and
196              * replace it with the resolved value
197              */
198             AcpiUtRemoveReference (StackDesc);
199             *StackPtr = ObjDesc;
200             break;
201 
202 
203         case ACPI_REFCLASS_INDEX:
204 
205             switch (StackDesc->Reference.TargetType)
206             {
207             case ACPI_TYPE_BUFFER_FIELD:
208 
209                 /* Just return - do not dereference */
210                 break;
211 
212 
213             case ACPI_TYPE_PACKAGE:
214 
215                 /* If method call or CopyObject - do not dereference */
216 
217                 if ((WalkState->Opcode == AML_INT_METHODCALL_OP) ||
218                     (WalkState->Opcode == AML_COPY_OP))
219                 {
220                     break;
221                 }
222 
223                 /* Otherwise, dereference the PackageIndex to a package element */
224 
225                 ObjDesc = *StackDesc->Reference.Where;
226                 if (ObjDesc)
227                 {
228                     /*
229                      * Valid object descriptor, copy pointer to return value
230                      * (i.e., dereference the package index)
231                      * Delete the ref object, increment the returned object
232                      */
233                     AcpiUtRemoveReference (StackDesc);
234                     AcpiUtAddReference (ObjDesc);
235                     *StackPtr = ObjDesc;
236                 }
237                 else
238                 {
239                     /*
240                      * A NULL object descriptor means an uninitialized element of
241                      * the package, can't dereference it
242                      */
243                     ACPI_ERROR ((AE_INFO,
244                         "Attempt to dereference an Index to NULL package element Idx=%p",
245                         StackDesc));
246                     Status = AE_AML_UNINITIALIZED_ELEMENT;
247                 }
248                 break;
249 
250 
251             default:
252 
253                 /* Invalid reference object */
254 
255                 ACPI_ERROR ((AE_INFO,
256                     "Unknown TargetType 0x%X in Index/Reference object %p",
257                     StackDesc->Reference.TargetType, StackDesc));
258                 Status = AE_AML_INTERNAL;
259                 break;
260             }
261             break;
262 
263 
264         case ACPI_REFCLASS_REFOF:
265         case ACPI_REFCLASS_DEBUG:
266         case ACPI_REFCLASS_TABLE:
267 
268             /* Just leave the object as-is, do not dereference */
269 
270             break;
271 
272         case ACPI_REFCLASS_NAME:   /* Reference to a named object */
273 
274             /* Dereference the name */
275 
276             if ((StackDesc->Reference.Node->Type == ACPI_TYPE_DEVICE) ||
277                 (StackDesc->Reference.Node->Type == ACPI_TYPE_THERMAL))
278             {
279                 /* These node types do not have 'real' subobjects */
280 
281                 *StackPtr = (void *) StackDesc->Reference.Node;
282             }
283             else
284             {
285                 /* Get the object pointed to by the namespace node */
286 
287                 *StackPtr = (StackDesc->Reference.Node)->Object;
288                 AcpiUtAddReference (*StackPtr);
289             }
290 
291             AcpiUtRemoveReference (StackDesc);
292             break;
293 
294         default:
295 
296             ACPI_ERROR ((AE_INFO,
297                 "Unknown Reference type 0x%X in %p", RefType, StackDesc));
298             Status = AE_AML_INTERNAL;
299             break;
300         }
301         break;
302 
303 
304     case ACPI_TYPE_BUFFER:
305 
306         Status = AcpiDsGetBufferArguments (StackDesc);
307         break;
308 
309 
310     case ACPI_TYPE_PACKAGE:
311 
312         Status = AcpiDsGetPackageArguments (StackDesc);
313         break;
314 
315 
316     case ACPI_TYPE_BUFFER_FIELD:
317     case ACPI_TYPE_LOCAL_REGION_FIELD:
318     case ACPI_TYPE_LOCAL_BANK_FIELD:
319     case ACPI_TYPE_LOCAL_INDEX_FIELD:
320 
321         ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "FieldRead SourceDesc=%p Type=%X\n",
322             StackDesc, StackDesc->Common.Type));
323 
324         Status = AcpiExReadDataFromField (WalkState, StackDesc, &ObjDesc);
325 
326         /* Remove a reference to the original operand, then override */
327 
328         AcpiUtRemoveReference (*StackPtr);
329         *StackPtr = (void *) ObjDesc;
330         break;
331 
332     default:
333         break;
334     }
335 
336     return_ACPI_STATUS (Status);
337 }
338 
339 
340 /*******************************************************************************
341  *
342  * FUNCTION:    AcpiExResolveMultiple
343  *
344  * PARAMETERS:  WalkState           - Current state (contains AML opcode)
345  *              Operand             - Starting point for resolution
346  *              ReturnType          - Where the object type is returned
347  *              ReturnDesc          - Where the resolved object is returned
348  *
349  * RETURN:      Status
350  *
351  * DESCRIPTION: Return the base object and type. Traverse a reference list if
352  *              necessary to get to the base object.
353  *
354  ******************************************************************************/
355 
356 ACPI_STATUS
357 AcpiExResolveMultiple (
358     ACPI_WALK_STATE         *WalkState,
359     ACPI_OPERAND_OBJECT     *Operand,
360     ACPI_OBJECT_TYPE        *ReturnType,
361     ACPI_OPERAND_OBJECT     **ReturnDesc)
362 {
363     ACPI_OPERAND_OBJECT     *ObjDesc = (void *) Operand;
364     ACPI_NAMESPACE_NODE     *Node;
365     ACPI_OBJECT_TYPE        Type;
366     ACPI_STATUS             Status;
367 
368 
369     ACPI_FUNCTION_TRACE (AcpiExResolveMultiple);
370 
371 
372     /* Operand can be either a namespace node or an operand descriptor */
373 
374     switch (ACPI_GET_DESCRIPTOR_TYPE (ObjDesc))
375     {
376     case ACPI_DESC_TYPE_OPERAND:
377         Type = ObjDesc->Common.Type;
378         break;
379 
380     case ACPI_DESC_TYPE_NAMED:
381         Type = ((ACPI_NAMESPACE_NODE *) ObjDesc)->Type;
382         ObjDesc = AcpiNsGetAttachedObject ((ACPI_NAMESPACE_NODE *) ObjDesc);
383 
384         /* If we had an Alias node, use the attached object for type info */
385 
386         if (Type == ACPI_TYPE_LOCAL_ALIAS)
387         {
388             Type = ((ACPI_NAMESPACE_NODE *) ObjDesc)->Type;
389             ObjDesc = AcpiNsGetAttachedObject ((ACPI_NAMESPACE_NODE *) ObjDesc);
390         }
391         break;
392 
393     default:
394         return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
395     }
396 
397     /* If type is anything other than a reference, we are done */
398 
399     if (Type != ACPI_TYPE_LOCAL_REFERENCE)
400     {
401         goto Exit;
402     }
403 
404     /*
405      * For reference objects created via the RefOf, Index, or Load/LoadTable
406      * operators, we need to get to the base object (as per the ACPI
407      * specification of the ObjectType and SizeOf operators). This means
408      * traversing the list of possibly many nested references.
409      */
410     while (ObjDesc->Common.Type == ACPI_TYPE_LOCAL_REFERENCE)
411     {
412         switch (ObjDesc->Reference.Class)
413         {
414         case ACPI_REFCLASS_REFOF:
415         case ACPI_REFCLASS_NAME:
416 
417             /* Dereference the reference pointer */
418 
419             if (ObjDesc->Reference.Class == ACPI_REFCLASS_REFOF)
420             {
421                 Node = ObjDesc->Reference.Object;
422             }
423             else /* AML_INT_NAMEPATH_OP */
424             {
425                 Node = ObjDesc->Reference.Node;
426             }
427 
428             /* All "References" point to a NS node */
429 
430             if (ACPI_GET_DESCRIPTOR_TYPE (Node) != ACPI_DESC_TYPE_NAMED)
431             {
432                 ACPI_ERROR ((AE_INFO,
433                     "Not a namespace node %p [%s]",
434                     Node, AcpiUtGetDescriptorName (Node)));
435                 return_ACPI_STATUS (AE_AML_INTERNAL);
436             }
437 
438             /* Get the attached object */
439 
440             ObjDesc = AcpiNsGetAttachedObject (Node);
441             if (!ObjDesc)
442             {
443                 /* No object, use the NS node type */
444 
445                 Type = AcpiNsGetType (Node);
446                 goto Exit;
447             }
448 
449             /* Check for circular references */
450 
451             if (ObjDesc == Operand)
452             {
453                 return_ACPI_STATUS (AE_AML_CIRCULAR_REFERENCE);
454             }
455             break;
456 
457 
458         case ACPI_REFCLASS_INDEX:
459 
460             /* Get the type of this reference (index into another object) */
461 
462             Type = ObjDesc->Reference.TargetType;
463             if (Type != ACPI_TYPE_PACKAGE)
464             {
465                 goto Exit;
466             }
467 
468             /*
469              * The main object is a package, we want to get the type
470              * of the individual package element that is referenced by
471              * the index.
472              *
473              * This could of course in turn be another reference object.
474              */
475             ObjDesc = *(ObjDesc->Reference.Where);
476             if (!ObjDesc)
477             {
478                 /* NULL package elements are allowed */
479 
480                 Type = 0; /* Uninitialized */
481                 goto Exit;
482             }
483             break;
484 
485 
486         case ACPI_REFCLASS_TABLE:
487 
488             Type = ACPI_TYPE_DDB_HANDLE;
489             goto Exit;
490 
491 
492         case ACPI_REFCLASS_LOCAL:
493         case ACPI_REFCLASS_ARG:
494 
495             if (ReturnDesc)
496             {
497                 Status = AcpiDsMethodDataGetValue (ObjDesc->Reference.Class,
498                             ObjDesc->Reference.Value, WalkState, &ObjDesc);
499                 if (ACPI_FAILURE (Status))
500                 {
501                     return_ACPI_STATUS (Status);
502                 }
503                 AcpiUtRemoveReference (ObjDesc);
504             }
505             else
506             {
507                 Status = AcpiDsMethodDataGetNode (ObjDesc->Reference.Class,
508                             ObjDesc->Reference.Value, WalkState, &Node);
509                 if (ACPI_FAILURE (Status))
510                 {
511                     return_ACPI_STATUS (Status);
512                 }
513 
514                 ObjDesc = AcpiNsGetAttachedObject (Node);
515                 if (!ObjDesc)
516                 {
517                     Type = ACPI_TYPE_ANY;
518                     goto Exit;
519                 }
520             }
521             break;
522 
523 
524         case ACPI_REFCLASS_DEBUG:
525 
526             /* The Debug Object is of type "DebugObject" */
527 
528             Type = ACPI_TYPE_DEBUG_OBJECT;
529             goto Exit;
530 
531 
532         default:
533 
534             ACPI_ERROR ((AE_INFO,
535                 "Unknown Reference Class 0x%2.2X", ObjDesc->Reference.Class));
536             return_ACPI_STATUS (AE_AML_INTERNAL);
537         }
538     }
539 
540     /*
541      * Now we are guaranteed to have an object that has not been created
542      * via the RefOf or Index operators.
543      */
544     Type = ObjDesc->Common.Type;
545 
546 
547 Exit:
548     /* Convert internal types to external types */
549 
550     switch (Type)
551     {
552     case ACPI_TYPE_LOCAL_REGION_FIELD:
553     case ACPI_TYPE_LOCAL_BANK_FIELD:
554     case ACPI_TYPE_LOCAL_INDEX_FIELD:
555 
556         Type = ACPI_TYPE_FIELD_UNIT;
557         break;
558 
559     case ACPI_TYPE_LOCAL_SCOPE:
560 
561         /* Per ACPI Specification, Scope is untyped */
562 
563         Type = ACPI_TYPE_ANY;
564         break;
565 
566     default:
567         /* No change to Type required */
568         break;
569     }
570 
571     *ReturnType = Type;
572     if (ReturnDesc)
573     {
574         *ReturnDesc = ObjDesc;
575     }
576     return_ACPI_STATUS (AE_OK);
577 }
578