exresolv.c revision 281075
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
57static ACPI_STATUS
58AcpiExResolveObjectToValue (
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
78ACPI_STATUS
79AcpiExResolveToValue (
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
149static ACPI_STATUS
150AcpiExResolveObjectToValue (
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
347ACPI_STATUS
348AcpiExResolveMultiple (
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 = (void *) Operand;
355    ACPI_NAMESPACE_NODE     *Node;
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 ((ACPI_NAMESPACE_NODE *) ObjDesc);
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        break;
385
386    default:
387        return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
388    }
389
390    /* If type is anything other than a reference, we are done */
391
392    if (Type != ACPI_TYPE_LOCAL_REFERENCE)
393    {
394        goto Exit;
395    }
396
397    /*
398     * For reference objects created via the RefOf, Index, or Load/LoadTable
399     * operators, we need to get to the base object (as per the ACPI
400     * specification of the ObjectType and SizeOf operators). This means
401     * traversing the list of possibly many nested references.
402     */
403    while (ObjDesc->Common.Type == ACPI_TYPE_LOCAL_REFERENCE)
404    {
405        switch (ObjDesc->Reference.Class)
406        {
407        case ACPI_REFCLASS_REFOF:
408        case ACPI_REFCLASS_NAME:
409
410            /* Dereference the reference pointer */
411
412            if (ObjDesc->Reference.Class == ACPI_REFCLASS_REFOF)
413            {
414                Node = ObjDesc->Reference.Object;
415            }
416            else /* AML_INT_NAMEPATH_OP */
417            {
418                Node = ObjDesc->Reference.Node;
419            }
420
421            /* All "References" point to a NS node */
422
423            if (ACPI_GET_DESCRIPTOR_TYPE (Node) != ACPI_DESC_TYPE_NAMED)
424            {
425                ACPI_ERROR ((AE_INFO,
426                    "Not a namespace node %p [%s]",
427                    Node, AcpiUtGetDescriptorName (Node)));
428                return_ACPI_STATUS (AE_AML_INTERNAL);
429            }
430
431            /* Get the attached object */
432
433            ObjDesc = AcpiNsGetAttachedObject (Node);
434            if (!ObjDesc)
435            {
436                /* No object, use the NS node type */
437
438                Type = AcpiNsGetType (Node);
439                goto Exit;
440            }
441
442            /* Check for circular references */
443
444            if (ObjDesc == Operand)
445            {
446                return_ACPI_STATUS (AE_AML_CIRCULAR_REFERENCE);
447            }
448            break;
449
450        case ACPI_REFCLASS_INDEX:
451
452            /* Get the type of this reference (index into another object) */
453
454            Type = ObjDesc->Reference.TargetType;
455            if (Type != ACPI_TYPE_PACKAGE)
456            {
457                goto Exit;
458            }
459
460            /*
461             * The main object is a package, we want to get the type
462             * of the individual package element that is referenced by
463             * the index.
464             *
465             * This could of course in turn be another reference object.
466             */
467            ObjDesc = *(ObjDesc->Reference.Where);
468            if (!ObjDesc)
469            {
470                /* NULL package elements are allowed */
471
472                Type = 0; /* Uninitialized */
473                goto Exit;
474            }
475            break;
476
477        case ACPI_REFCLASS_TABLE:
478
479            Type = ACPI_TYPE_DDB_HANDLE;
480            goto Exit;
481
482        case ACPI_REFCLASS_LOCAL:
483        case ACPI_REFCLASS_ARG:
484
485            if (ReturnDesc)
486            {
487                Status = AcpiDsMethodDataGetValue (ObjDesc->Reference.Class,
488                            ObjDesc->Reference.Value, WalkState, &ObjDesc);
489                if (ACPI_FAILURE (Status))
490                {
491                    return_ACPI_STATUS (Status);
492                }
493                AcpiUtRemoveReference (ObjDesc);
494            }
495            else
496            {
497                Status = AcpiDsMethodDataGetNode (ObjDesc->Reference.Class,
498                            ObjDesc->Reference.Value, WalkState, &Node);
499                if (ACPI_FAILURE (Status))
500                {
501                    return_ACPI_STATUS (Status);
502                }
503
504                ObjDesc = AcpiNsGetAttachedObject (Node);
505                if (!ObjDesc)
506                {
507                    Type = ACPI_TYPE_ANY;
508                    goto Exit;
509                }
510            }
511            break;
512
513        case ACPI_REFCLASS_DEBUG:
514
515            /* The Debug Object is of type "DebugObject" */
516
517            Type = ACPI_TYPE_DEBUG_OBJECT;
518            goto Exit;
519
520        default:
521
522            ACPI_ERROR ((AE_INFO,
523                "Unknown Reference Class 0x%2.2X", ObjDesc->Reference.Class));
524            return_ACPI_STATUS (AE_AML_INTERNAL);
525        }
526    }
527
528    /*
529     * Now we are guaranteed to have an object that has not been created
530     * via the RefOf or Index operators.
531     */
532    Type = ObjDesc->Common.Type;
533
534
535Exit:
536    /* Convert internal types to external types */
537
538    switch (Type)
539    {
540    case ACPI_TYPE_LOCAL_REGION_FIELD:
541    case ACPI_TYPE_LOCAL_BANK_FIELD:
542    case ACPI_TYPE_LOCAL_INDEX_FIELD:
543
544        Type = ACPI_TYPE_FIELD_UNIT;
545        break;
546
547    case ACPI_TYPE_LOCAL_SCOPE:
548
549        /* Per ACPI Specification, Scope is untyped */
550
551        Type = ACPI_TYPE_ANY;
552        break;
553
554    default:
555
556        /* No change to Type required */
557
558        break;
559    }
560
561    *ReturnType = Type;
562    if (ReturnDesc)
563    {
564        *ReturnDesc = ObjDesc;
565    }
566    return_ACPI_STATUS (AE_OK);
567}
568