exresolv.c revision 241973
1/******************************************************************************
2 *
3 * Module Name: exresolv - AML Interpreter object resolution
4 *
5 *****************************************************************************/
6
7/*
8 * Copyright (C) 2000 - 2012, 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
59static ACPI_STATUS
60AcpiExResolveObjectToValue (
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
80ACPI_STATUS
81AcpiExResolveToValue (
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
151static ACPI_STATUS
152AcpiExResolveObjectToValue (
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
356ACPI_STATUS
357AcpiExResolveMultiple (
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
547Exit:
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