exresolv.c revision 217365
1
2/******************************************************************************
3 *
4 * Module Name: exresolv - AML Interpreter object resolution
5 *
6 *****************************************************************************/
7
8/*
9 * Copyright (C) 2000 - 2011, Intel Corp.
10 * All rights reserved.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 *    notice, this list of conditions, and the following disclaimer,
17 *    without modification.
18 * 2. Redistributions in binary form must reproduce at minimum a disclaimer
19 *    substantially similar to the "NO WARRANTY" disclaimer below
20 *    ("Disclaimer") and any redistribution must be conditioned upon
21 *    including a substantially similar Disclaimer requirement for further
22 *    binary redistribution.
23 * 3. Neither the names of the above-listed copyright holders nor the names
24 *    of any contributors may be used to endorse or promote products derived
25 *    from this software without specific prior written permission.
26 *
27 * Alternatively, this software may be distributed under the terms of the
28 * GNU General Public License ("GPL") version 2 as published by the Free
29 * Software Foundation.
30 *
31 * NO WARRANTY
32 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
33 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
34 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
35 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
36 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
37 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
38 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
39 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
40 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
41 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
42 * POSSIBILITY OF SUCH DAMAGES.
43 */
44
45#define __EXRESOLV_C__
46
47#include <contrib/dev/acpica/include/acpi.h>
48#include <contrib/dev/acpica/include/accommon.h>
49#include <contrib/dev/acpica/include/amlcode.h>
50#include <contrib/dev/acpica/include/acdispat.h>
51#include <contrib/dev/acpica/include/acinterp.h>
52#include <contrib/dev/acpica/include/acnamesp.h>
53
54
55#define _COMPONENT          ACPI_EXECUTER
56        ACPI_MODULE_NAME    ("exresolv")
57
58/* Local prototypes */
59
60static ACPI_STATUS
61AcpiExResolveObjectToValue (
62    ACPI_OPERAND_OBJECT     **StackPtr,
63    ACPI_WALK_STATE         *WalkState);
64
65
66/*******************************************************************************
67 *
68 * FUNCTION:    AcpiExResolveToValue
69 *
70 * PARAMETERS:  **StackPtr          - Points to entry on ObjStack, which can
71 *                                    be either an (ACPI_OPERAND_OBJECT *)
72 *                                    or an ACPI_HANDLE.
73 *              WalkState           - Current method state
74 *
75 * RETURN:      Status
76 *
77 * DESCRIPTION: Convert Reference objects to values
78 *
79 ******************************************************************************/
80
81ACPI_STATUS
82AcpiExResolveToValue (
83    ACPI_OPERAND_OBJECT     **StackPtr,
84    ACPI_WALK_STATE         *WalkState)
85{
86    ACPI_STATUS             Status;
87
88
89    ACPI_FUNCTION_TRACE_PTR (ExResolveToValue, StackPtr);
90
91
92    if (!StackPtr || !*StackPtr)
93    {
94        ACPI_ERROR ((AE_INFO, "Internal - null pointer"));
95        return_ACPI_STATUS (AE_AML_NO_OPERAND);
96    }
97
98    /*
99     * The entity pointed to by the StackPtr can be either
100     * 1) A valid ACPI_OPERAND_OBJECT, or
101     * 2) A ACPI_NAMESPACE_NODE (NamedObj)
102     */
103    if (ACPI_GET_DESCRIPTOR_TYPE (*StackPtr) == ACPI_DESC_TYPE_OPERAND)
104    {
105        Status = AcpiExResolveObjectToValue (StackPtr, WalkState);
106        if (ACPI_FAILURE (Status))
107        {
108            return_ACPI_STATUS (Status);
109        }
110
111        if (!*StackPtr)
112        {
113            ACPI_ERROR ((AE_INFO, "Internal - null pointer"));
114            return_ACPI_STATUS (AE_AML_NO_OPERAND);
115        }
116    }
117
118    /*
119     * Object on the stack may have changed if AcpiExResolveObjectToValue()
120     * was called (i.e., we can't use an _else_ here.)
121     */
122    if (ACPI_GET_DESCRIPTOR_TYPE (*StackPtr) == ACPI_DESC_TYPE_NAMED)
123    {
124        Status = AcpiExResolveNodeToValue (
125                        ACPI_CAST_INDIRECT_PTR (ACPI_NAMESPACE_NODE, StackPtr),
126                        WalkState);
127        if (ACPI_FAILURE (Status))
128        {
129            return_ACPI_STATUS (Status);
130        }
131    }
132
133    ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Resolved object %p\n", *StackPtr));
134    return_ACPI_STATUS (AE_OK);
135}
136
137
138/*******************************************************************************
139 *
140 * FUNCTION:    AcpiExResolveObjectToValue
141 *
142 * PARAMETERS:  StackPtr        - Pointer to an internal object
143 *              WalkState       - Current method state
144 *
145 * RETURN:      Status
146 *
147 * DESCRIPTION: Retrieve the value from an internal object. The Reference type
148 *              uses the associated AML opcode to determine the value.
149 *
150 ******************************************************************************/
151
152static ACPI_STATUS
153AcpiExResolveObjectToValue (
154    ACPI_OPERAND_OBJECT     **StackPtr,
155    ACPI_WALK_STATE         *WalkState)
156{
157    ACPI_STATUS             Status = AE_OK;
158    ACPI_OPERAND_OBJECT     *StackDesc;
159    ACPI_OPERAND_OBJECT     *ObjDesc = NULL;
160    UINT8                   RefType;
161
162
163    ACPI_FUNCTION_TRACE (ExResolveObjectToValue);
164
165
166    StackDesc = *StackPtr;
167
168    /* This is an ACPI_OPERAND_OBJECT  */
169
170    switch (StackDesc->Common.Type)
171    {
172    case ACPI_TYPE_LOCAL_REFERENCE:
173
174        RefType = StackDesc->Reference.Class;
175
176        switch (RefType)
177        {
178        case ACPI_REFCLASS_LOCAL:
179        case ACPI_REFCLASS_ARG:
180
181            /*
182             * Get the local from the method's state info
183             * Note: this increments the local's object reference count
184             */
185            Status = AcpiDsMethodDataGetValue (RefType,
186                            StackDesc->Reference.Value, WalkState, &ObjDesc);
187            if (ACPI_FAILURE (Status))
188            {
189                return_ACPI_STATUS (Status);
190            }
191
192            ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "[Arg/Local %X] ValueObj is %p\n",
193                StackDesc->Reference.Value, ObjDesc));
194
195            /*
196             * Now we can delete the original Reference Object and
197             * replace it with the resolved value
198             */
199            AcpiUtRemoveReference (StackDesc);
200            *StackPtr = ObjDesc;
201            break;
202
203
204        case ACPI_REFCLASS_INDEX:
205
206            switch (StackDesc->Reference.TargetType)
207            {
208            case ACPI_TYPE_BUFFER_FIELD:
209
210                /* Just return - do not dereference */
211                break;
212
213
214            case ACPI_TYPE_PACKAGE:
215
216                /* If method call or CopyObject - do not dereference */
217
218                if ((WalkState->Opcode == AML_INT_METHODCALL_OP) ||
219                    (WalkState->Opcode == AML_COPY_OP))
220                {
221                    break;
222                }
223
224                /* Otherwise, dereference the PackageIndex to a package element */
225
226                ObjDesc = *StackDesc->Reference.Where;
227                if (ObjDesc)
228                {
229                    /*
230                     * Valid object descriptor, copy pointer to return value
231                     * (i.e., dereference the package index)
232                     * Delete the ref object, increment the returned object
233                     */
234                    AcpiUtRemoveReference (StackDesc);
235                    AcpiUtAddReference (ObjDesc);
236                    *StackPtr = ObjDesc;
237                }
238                else
239                {
240                    /*
241                     * A NULL object descriptor means an uninitialized element of
242                     * the package, can't dereference it
243                     */
244                    ACPI_ERROR ((AE_INFO,
245                        "Attempt to dereference an Index to NULL package element Idx=%p",
246                        StackDesc));
247                    Status = AE_AML_UNINITIALIZED_ELEMENT;
248                }
249                break;
250
251
252            default:
253
254                /* Invalid reference object */
255
256                ACPI_ERROR ((AE_INFO,
257                    "Unknown TargetType 0x%X in Index/Reference object %p",
258                    StackDesc->Reference.TargetType, StackDesc));
259                Status = AE_AML_INTERNAL;
260                break;
261            }
262            break;
263
264
265        case ACPI_REFCLASS_REFOF:
266        case ACPI_REFCLASS_DEBUG:
267        case ACPI_REFCLASS_TABLE:
268
269            /* Just leave the object as-is, do not dereference */
270
271            break;
272
273        case ACPI_REFCLASS_NAME:   /* Reference to a named object */
274
275            /* Dereference the name */
276
277            if ((StackDesc->Reference.Node->Type == ACPI_TYPE_DEVICE) ||
278                (StackDesc->Reference.Node->Type == ACPI_TYPE_THERMAL))
279            {
280                /* These node types do not have 'real' subobjects */
281
282                *StackPtr = (void *) StackDesc->Reference.Node;
283            }
284            else
285            {
286                /* Get the object pointed to by the namespace node */
287
288                *StackPtr = (StackDesc->Reference.Node)->Object;
289                AcpiUtAddReference (*StackPtr);
290            }
291
292            AcpiUtRemoveReference (StackDesc);
293            break;
294
295        default:
296
297            ACPI_ERROR ((AE_INFO,
298                "Unknown Reference type 0x%X in %p", RefType, StackDesc));
299            Status = AE_AML_INTERNAL;
300            break;
301        }
302        break;
303
304
305    case ACPI_TYPE_BUFFER:
306
307        Status = AcpiDsGetBufferArguments (StackDesc);
308        break;
309
310
311    case ACPI_TYPE_PACKAGE:
312
313        Status = AcpiDsGetPackageArguments (StackDesc);
314        break;
315
316
317    case ACPI_TYPE_BUFFER_FIELD:
318    case ACPI_TYPE_LOCAL_REGION_FIELD:
319    case ACPI_TYPE_LOCAL_BANK_FIELD:
320    case ACPI_TYPE_LOCAL_INDEX_FIELD:
321
322        ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "FieldRead SourceDesc=%p Type=%X\n",
323            StackDesc, StackDesc->Common.Type));
324
325        Status = AcpiExReadDataFromField (WalkState, StackDesc, &ObjDesc);
326
327        /* Remove a reference to the original operand, then override */
328
329        AcpiUtRemoveReference (*StackPtr);
330        *StackPtr = (void *) ObjDesc;
331        break;
332
333    default:
334        break;
335    }
336
337    return_ACPI_STATUS (Status);
338}
339
340
341/*******************************************************************************
342 *
343 * FUNCTION:    AcpiExResolveMultiple
344 *
345 * PARAMETERS:  WalkState           - Current state (contains AML opcode)
346 *              Operand             - Starting point for resolution
347 *              ReturnType          - Where the object type is returned
348 *              ReturnDesc          - Where the resolved object is returned
349 *
350 * RETURN:      Status
351 *
352 * DESCRIPTION: Return the base object and type.  Traverse a reference list if
353 *              necessary to get to the base object.
354 *
355 ******************************************************************************/
356
357ACPI_STATUS
358AcpiExResolveMultiple (
359    ACPI_WALK_STATE         *WalkState,
360    ACPI_OPERAND_OBJECT     *Operand,
361    ACPI_OBJECT_TYPE        *ReturnType,
362    ACPI_OPERAND_OBJECT     **ReturnDesc)
363{
364    ACPI_OPERAND_OBJECT     *ObjDesc = (void *) Operand;
365    ACPI_NAMESPACE_NODE     *Node;
366    ACPI_OBJECT_TYPE        Type;
367    ACPI_STATUS             Status;
368
369
370    ACPI_FUNCTION_TRACE (AcpiExResolveMultiple);
371
372
373    /* Operand can be either a namespace node or an operand descriptor */
374
375    switch (ACPI_GET_DESCRIPTOR_TYPE (ObjDesc))
376    {
377    case ACPI_DESC_TYPE_OPERAND:
378        Type = ObjDesc->Common.Type;
379        break;
380
381    case ACPI_DESC_TYPE_NAMED:
382        Type = ((ACPI_NAMESPACE_NODE *) ObjDesc)->Type;
383        ObjDesc = AcpiNsGetAttachedObject ((ACPI_NAMESPACE_NODE *) ObjDesc);
384
385        /* If we had an Alias node, use the attached object for type info */
386
387        if (Type == ACPI_TYPE_LOCAL_ALIAS)
388        {
389            Type = ((ACPI_NAMESPACE_NODE *) ObjDesc)->Type;
390            ObjDesc = AcpiNsGetAttachedObject ((ACPI_NAMESPACE_NODE *) ObjDesc);
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
459        case ACPI_REFCLASS_INDEX:
460
461            /* Get the type of this reference (index into another object) */
462
463            Type = ObjDesc->Reference.TargetType;
464            if (Type != ACPI_TYPE_PACKAGE)
465            {
466                goto Exit;
467            }
468
469            /*
470             * The main object is a package, we want to get the type
471             * of the individual package element that is referenced by
472             * the index.
473             *
474             * This could of course in turn be another reference object.
475             */
476            ObjDesc = *(ObjDesc->Reference.Where);
477            if (!ObjDesc)
478            {
479                /* NULL package elements are allowed */
480
481                Type = 0; /* Uninitialized */
482                goto Exit;
483            }
484            break;
485
486
487        case ACPI_REFCLASS_TABLE:
488
489            Type = ACPI_TYPE_DDB_HANDLE;
490            goto Exit;
491
492
493        case ACPI_REFCLASS_LOCAL:
494        case ACPI_REFCLASS_ARG:
495
496            if (ReturnDesc)
497            {
498                Status = AcpiDsMethodDataGetValue (ObjDesc->Reference.Class,
499                            ObjDesc->Reference.Value, WalkState, &ObjDesc);
500                if (ACPI_FAILURE (Status))
501                {
502                    return_ACPI_STATUS (Status);
503                }
504                AcpiUtRemoveReference (ObjDesc);
505            }
506            else
507            {
508                Status = AcpiDsMethodDataGetNode (ObjDesc->Reference.Class,
509                            ObjDesc->Reference.Value, WalkState, &Node);
510                if (ACPI_FAILURE (Status))
511                {
512                    return_ACPI_STATUS (Status);
513                }
514
515                ObjDesc = AcpiNsGetAttachedObject (Node);
516                if (!ObjDesc)
517                {
518                    Type = ACPI_TYPE_ANY;
519                    goto Exit;
520                }
521            }
522            break;
523
524
525        case ACPI_REFCLASS_DEBUG:
526
527            /* The Debug Object is of type "DebugObject" */
528
529            Type = ACPI_TYPE_DEBUG_OBJECT;
530            goto Exit;
531
532
533        default:
534
535            ACPI_ERROR ((AE_INFO,
536                "Unknown Reference Class 0x%2.2X", ObjDesc->Reference.Class));
537            return_ACPI_STATUS (AE_AML_INTERNAL);
538        }
539    }
540
541    /*
542     * Now we are guaranteed to have an object that has not been created
543     * via the RefOf or Index operators.
544     */
545    Type = ObjDesc->Common.Type;
546
547
548Exit:
549    /* Convert internal types to external types */
550
551    switch (Type)
552    {
553    case ACPI_TYPE_LOCAL_REGION_FIELD:
554    case ACPI_TYPE_LOCAL_BANK_FIELD:
555    case ACPI_TYPE_LOCAL_INDEX_FIELD:
556
557        Type = ACPI_TYPE_FIELD_UNIT;
558        break;
559
560    case ACPI_TYPE_LOCAL_SCOPE:
561
562        /* Per ACPI Specification, Scope is untyped */
563
564        Type = ACPI_TYPE_ANY;
565        break;
566
567    default:
568        /* No change to Type required */
569        break;
570    }
571
572    *ReturnType = Type;
573    if (ReturnDesc)
574    {
575        *ReturnDesc = ObjDesc;
576    }
577    return_ACPI_STATUS (AE_OK);
578}
579
580
581