xref: /freebsd/sys/contrib/dev/acpica/components/executer/exresolv.c (revision 39ee7a7a6bdd1557b1c3532abf60d139798ac88b)
1 /******************************************************************************
2  *
3  * Module Name: exresolv - AML Interpreter object resolution
4  *
5  *****************************************************************************/
6 
7 /*
8  * Copyright (C) 2000 - 2015, 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 <contrib/dev/acpica/include/acpi.h>
45 #include <contrib/dev/acpica/include/accommon.h>
46 #include <contrib/dev/acpica/include/amlcode.h>
47 #include <contrib/dev/acpica/include/acdispat.h>
48 #include <contrib/dev/acpica/include/acinterp.h>
49 #include <contrib/dev/acpica/include/acnamesp.h>
50 
51 
52 #define _COMPONENT          ACPI_EXECUTER
53         ACPI_MODULE_NAME    ("exresolv")
54 
55 /* Local prototypes */
56 
57 static ACPI_STATUS
58 AcpiExResolveObjectToValue (
59     ACPI_OPERAND_OBJECT     **StackPtr,
60     ACPI_WALK_STATE         *WalkState);
61 
62 
63 /*******************************************************************************
64  *
65  * FUNCTION:    AcpiExResolveToValue
66  *
67  * PARAMETERS:  **StackPtr          - Points to entry on ObjStack, which can
68  *                                    be either an (ACPI_OPERAND_OBJECT *)
69  *                                    or an ACPI_HANDLE.
70  *              WalkState           - Current method state
71  *
72  * RETURN:      Status
73  *
74  * DESCRIPTION: Convert Reference objects to values
75  *
76  ******************************************************************************/
77 
78 ACPI_STATUS
79 AcpiExResolveToValue (
80     ACPI_OPERAND_OBJECT     **StackPtr,
81     ACPI_WALK_STATE         *WalkState)
82 {
83     ACPI_STATUS             Status;
84 
85 
86     ACPI_FUNCTION_TRACE_PTR (ExResolveToValue, StackPtr);
87 
88 
89     if (!StackPtr || !*StackPtr)
90     {
91         ACPI_ERROR ((AE_INFO, "Internal - null pointer"));
92         return_ACPI_STATUS (AE_AML_NO_OPERAND);
93     }
94 
95     /*
96      * The entity pointed to by the StackPtr can be either
97      * 1) A valid ACPI_OPERAND_OBJECT, or
98      * 2) A ACPI_NAMESPACE_NODE (NamedObj)
99      */
100     if (ACPI_GET_DESCRIPTOR_TYPE (*StackPtr) == ACPI_DESC_TYPE_OPERAND)
101     {
102         Status = AcpiExResolveObjectToValue (StackPtr, WalkState);
103         if (ACPI_FAILURE (Status))
104         {
105             return_ACPI_STATUS (Status);
106         }
107 
108         if (!*StackPtr)
109         {
110             ACPI_ERROR ((AE_INFO, "Internal - null pointer"));
111             return_ACPI_STATUS (AE_AML_NO_OPERAND);
112         }
113     }
114 
115     /*
116      * Object on the stack may have changed if AcpiExResolveObjectToValue()
117      * was called (i.e., we can't use an _else_ here.)
118      */
119     if (ACPI_GET_DESCRIPTOR_TYPE (*StackPtr) == ACPI_DESC_TYPE_NAMED)
120     {
121         Status = AcpiExResolveNodeToValue (
122                         ACPI_CAST_INDIRECT_PTR (ACPI_NAMESPACE_NODE, StackPtr),
123                         WalkState);
124         if (ACPI_FAILURE (Status))
125         {
126             return_ACPI_STATUS (Status);
127         }
128     }
129 
130     ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Resolved object %p\n", *StackPtr));
131     return_ACPI_STATUS (AE_OK);
132 }
133 
134 
135 /*******************************************************************************
136  *
137  * FUNCTION:    AcpiExResolveObjectToValue
138  *
139  * PARAMETERS:  StackPtr        - Pointer to an internal object
140  *              WalkState       - Current method state
141  *
142  * RETURN:      Status
143  *
144  * DESCRIPTION: Retrieve the value from an internal object. The Reference type
145  *              uses the associated AML opcode to determine the value.
146  *
147  ******************************************************************************/
148 
149 static ACPI_STATUS
150 AcpiExResolveObjectToValue (
151     ACPI_OPERAND_OBJECT     **StackPtr,
152     ACPI_WALK_STATE         *WalkState)
153 {
154     ACPI_STATUS             Status = AE_OK;
155     ACPI_OPERAND_OBJECT     *StackDesc;
156     ACPI_OPERAND_OBJECT     *ObjDesc = NULL;
157     UINT8                   RefType;
158 
159 
160     ACPI_FUNCTION_TRACE (ExResolveObjectToValue);
161 
162 
163     StackDesc = *StackPtr;
164 
165     /* This is an object of type ACPI_OPERAND_OBJECT */
166 
167     switch (StackDesc->Common.Type)
168     {
169     case ACPI_TYPE_LOCAL_REFERENCE:
170 
171         RefType = StackDesc->Reference.Class;
172 
173         switch (RefType)
174         {
175         case ACPI_REFCLASS_LOCAL:
176         case ACPI_REFCLASS_ARG:
177             /*
178              * Get the local from the method's state info
179              * Note: this increments the local's object reference count
180              */
181             Status = AcpiDsMethodDataGetValue (RefType,
182                             StackDesc->Reference.Value, WalkState, &ObjDesc);
183             if (ACPI_FAILURE (Status))
184             {
185                 return_ACPI_STATUS (Status);
186             }
187 
188             ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "[Arg/Local %X] ValueObj is %p\n",
189                 StackDesc->Reference.Value, ObjDesc));
190 
191             /*
192              * Now we can delete the original Reference Object and
193              * replace it with the resolved value
194              */
195             AcpiUtRemoveReference (StackDesc);
196             *StackPtr = ObjDesc;
197             break;
198 
199         case ACPI_REFCLASS_INDEX:
200 
201             switch (StackDesc->Reference.TargetType)
202             {
203             case ACPI_TYPE_BUFFER_FIELD:
204 
205                 /* Just return - do not dereference */
206                 break;
207 
208             case ACPI_TYPE_PACKAGE:
209 
210                 /* If method call or CopyObject - do not dereference */
211 
212                 if ((WalkState->Opcode == AML_INT_METHODCALL_OP) ||
213                     (WalkState->Opcode == AML_COPY_OP))
214                 {
215                     break;
216                 }
217 
218                 /* Otherwise, dereference the PackageIndex to a package element */
219 
220                 ObjDesc = *StackDesc->Reference.Where;
221                 if (ObjDesc)
222                 {
223                     /*
224                      * Valid object descriptor, copy pointer to return value
225                      * (i.e., dereference the package index)
226                      * Delete the ref object, increment the returned object
227                      */
228                     AcpiUtRemoveReference (StackDesc);
229                     AcpiUtAddReference (ObjDesc);
230                     *StackPtr = ObjDesc;
231                 }
232                 else
233                 {
234                     /*
235                      * A NULL object descriptor means an uninitialized element of
236                      * the package, can't dereference it
237                      */
238                     ACPI_ERROR ((AE_INFO,
239                         "Attempt to dereference an Index to NULL package element Idx=%p",
240                         StackDesc));
241                     Status = AE_AML_UNINITIALIZED_ELEMENT;
242                 }
243                 break;
244 
245             default:
246 
247                 /* Invalid reference object */
248 
249                 ACPI_ERROR ((AE_INFO,
250                     "Unknown TargetType 0x%X in Index/Reference object %p",
251                     StackDesc->Reference.TargetType, StackDesc));
252                 Status = AE_AML_INTERNAL;
253                 break;
254             }
255             break;
256 
257         case ACPI_REFCLASS_REFOF:
258         case ACPI_REFCLASS_DEBUG:
259         case ACPI_REFCLASS_TABLE:
260 
261             /* Just leave the object as-is, do not dereference */
262 
263             break;
264 
265         case ACPI_REFCLASS_NAME:   /* Reference to a named object */
266 
267             /* Dereference the name */
268 
269             if ((StackDesc->Reference.Node->Type == ACPI_TYPE_DEVICE) ||
270                 (StackDesc->Reference.Node->Type == ACPI_TYPE_THERMAL))
271             {
272                 /* These node types do not have 'real' subobjects */
273 
274                 *StackPtr = (void *) StackDesc->Reference.Node;
275             }
276             else
277             {
278                 /* Get the object pointed to by the namespace node */
279 
280                 *StackPtr = (StackDesc->Reference.Node)->Object;
281                 AcpiUtAddReference (*StackPtr);
282             }
283 
284             AcpiUtRemoveReference (StackDesc);
285             break;
286 
287         default:
288 
289             ACPI_ERROR ((AE_INFO,
290                 "Unknown Reference type 0x%X in %p", RefType, StackDesc));
291             Status = AE_AML_INTERNAL;
292             break;
293         }
294         break;
295 
296     case ACPI_TYPE_BUFFER:
297 
298         Status = AcpiDsGetBufferArguments (StackDesc);
299         break;
300 
301     case ACPI_TYPE_PACKAGE:
302 
303         Status = AcpiDsGetPackageArguments (StackDesc);
304         break;
305 
306     case ACPI_TYPE_BUFFER_FIELD:
307     case ACPI_TYPE_LOCAL_REGION_FIELD:
308     case ACPI_TYPE_LOCAL_BANK_FIELD:
309     case ACPI_TYPE_LOCAL_INDEX_FIELD:
310 
311         ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "FieldRead SourceDesc=%p Type=%X\n",
312             StackDesc, StackDesc->Common.Type));
313 
314         Status = AcpiExReadDataFromField (WalkState, StackDesc, &ObjDesc);
315 
316         /* Remove a reference to the original operand, then override */
317 
318         AcpiUtRemoveReference (*StackPtr);
319         *StackPtr = (void *) ObjDesc;
320         break;
321 
322     default:
323 
324         break;
325     }
326 
327     return_ACPI_STATUS (Status);
328 }
329 
330 
331 /*******************************************************************************
332  *
333  * FUNCTION:    AcpiExResolveMultiple
334  *
335  * PARAMETERS:  WalkState           - Current state (contains AML opcode)
336  *              Operand             - Starting point for resolution
337  *              ReturnType          - Where the object type is returned
338  *              ReturnDesc          - Where the resolved object is returned
339  *
340  * RETURN:      Status
341  *
342  * DESCRIPTION: Return the base object and type. Traverse a reference list if
343  *              necessary to get to the base object.
344  *
345  ******************************************************************************/
346 
347 ACPI_STATUS
348 AcpiExResolveMultiple (
349     ACPI_WALK_STATE         *WalkState,
350     ACPI_OPERAND_OBJECT     *Operand,
351     ACPI_OBJECT_TYPE        *ReturnType,
352     ACPI_OPERAND_OBJECT     **ReturnDesc)
353 {
354     ACPI_OPERAND_OBJECT     *ObjDesc = ACPI_CAST_PTR (void, Operand);
355     ACPI_NAMESPACE_NODE     *Node = ACPI_CAST_PTR (ACPI_NAMESPACE_NODE, Operand);
356     ACPI_OBJECT_TYPE        Type;
357     ACPI_STATUS             Status;
358 
359 
360     ACPI_FUNCTION_TRACE (AcpiExResolveMultiple);
361 
362 
363     /* Operand can be either a namespace node or an operand descriptor */
364 
365     switch (ACPI_GET_DESCRIPTOR_TYPE (ObjDesc))
366     {
367     case ACPI_DESC_TYPE_OPERAND:
368 
369         Type = ObjDesc->Common.Type;
370         break;
371 
372     case ACPI_DESC_TYPE_NAMED:
373 
374         Type = ((ACPI_NAMESPACE_NODE *) ObjDesc)->Type;
375         ObjDesc = AcpiNsGetAttachedObject (Node);
376 
377         /* If we had an Alias node, use the attached object for type info */
378 
379         if (Type == ACPI_TYPE_LOCAL_ALIAS)
380         {
381             Type = ((ACPI_NAMESPACE_NODE *) ObjDesc)->Type;
382             ObjDesc = AcpiNsGetAttachedObject ((ACPI_NAMESPACE_NODE *) ObjDesc);
383         }
384 
385         if (!ObjDesc)
386         {
387             ACPI_ERROR ((AE_INFO,
388                 "[%4.4s] Node is unresolved or uninitialized",
389                 AcpiUtGetNodeName (Node)));
390             return_ACPI_STATUS (AE_AML_UNINITIALIZED_NODE);
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         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         case ACPI_REFCLASS_TABLE:
486 
487             Type = ACPI_TYPE_DDB_HANDLE;
488             goto Exit;
489 
490         case ACPI_REFCLASS_LOCAL:
491         case ACPI_REFCLASS_ARG:
492 
493             if (ReturnDesc)
494             {
495                 Status = AcpiDsMethodDataGetValue (ObjDesc->Reference.Class,
496                             ObjDesc->Reference.Value, WalkState, &ObjDesc);
497                 if (ACPI_FAILURE (Status))
498                 {
499                     return_ACPI_STATUS (Status);
500                 }
501                 AcpiUtRemoveReference (ObjDesc);
502             }
503             else
504             {
505                 Status = AcpiDsMethodDataGetNode (ObjDesc->Reference.Class,
506                             ObjDesc->Reference.Value, WalkState, &Node);
507                 if (ACPI_FAILURE (Status))
508                 {
509                     return_ACPI_STATUS (Status);
510                 }
511 
512                 ObjDesc = AcpiNsGetAttachedObject (Node);
513                 if (!ObjDesc)
514                 {
515                     Type = ACPI_TYPE_ANY;
516                     goto Exit;
517                 }
518             }
519             break;
520 
521         case ACPI_REFCLASS_DEBUG:
522 
523             /* The Debug Object is of type "DebugObject" */
524 
525             Type = ACPI_TYPE_DEBUG_OBJECT;
526             goto Exit;
527 
528         default:
529 
530             ACPI_ERROR ((AE_INFO,
531                 "Unknown Reference Class 0x%2.2X", ObjDesc->Reference.Class));
532             return_ACPI_STATUS (AE_AML_INTERNAL);
533         }
534     }
535 
536     /*
537      * Now we are guaranteed to have an object that has not been created
538      * via the RefOf or Index operators.
539      */
540     Type = ObjDesc->Common.Type;
541 
542 
543 Exit:
544     /* Convert internal types to external types */
545 
546     switch (Type)
547     {
548     case ACPI_TYPE_LOCAL_REGION_FIELD:
549     case ACPI_TYPE_LOCAL_BANK_FIELD:
550     case ACPI_TYPE_LOCAL_INDEX_FIELD:
551 
552         Type = ACPI_TYPE_FIELD_UNIT;
553         break;
554 
555     case ACPI_TYPE_LOCAL_SCOPE:
556 
557         /* Per ACPI Specification, Scope is untyped */
558 
559         Type = ACPI_TYPE_ANY;
560         break;
561 
562     default:
563 
564         /* No change to Type required */
565 
566         break;
567     }
568 
569     *ReturnType = Type;
570     if (ReturnDesc)
571     {
572         *ReturnDesc = ObjDesc;
573     }
574     return_ACPI_STATUS (AE_OK);
575 }
576