nseval.c revision 217365
1/*******************************************************************************
2 *
3 * Module Name: nseval - Object evaluation, includes control method execution
4 *
5 ******************************************************************************/
6
7/*
8 * Copyright (C) 2000 - 2011, 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 __NSEVAL_C__
45
46#include <contrib/dev/acpica/include/acpi.h>
47#include <contrib/dev/acpica/include/accommon.h>
48#include <contrib/dev/acpica/include/acparser.h>
49#include <contrib/dev/acpica/include/acinterp.h>
50#include <contrib/dev/acpica/include/acnamesp.h>
51
52
53#define _COMPONENT          ACPI_NAMESPACE
54        ACPI_MODULE_NAME    ("nseval")
55
56/* Local prototypes */
57
58static void
59AcpiNsExecModuleCode (
60    ACPI_OPERAND_OBJECT     *MethodObj,
61    ACPI_EVALUATE_INFO      *Info);
62
63
64/*******************************************************************************
65 *
66 * FUNCTION:    AcpiNsEvaluate
67 *
68 * PARAMETERS:  Info            - Evaluation info block, contains:
69 *                  PrefixNode      - Prefix or Method/Object Node to execute
70 *                  Pathname        - Name of method to execute, If NULL, the
71 *                                    Node is the object to execute
72 *                  Parameters      - List of parameters to pass to the method,
73 *                                    terminated by NULL. Params itself may be
74 *                                    NULL if no parameters are being passed.
75 *                  ReturnObject    - Where to put method's return value (if
76 *                                    any). If NULL, no value is returned.
77 *                  ParameterType   - Type of Parameter list
78 *                  ReturnObject    - Where to put method's return value (if
79 *                                    any). If NULL, no value is returned.
80 *                  Flags           - ACPI_IGNORE_RETURN_VALUE to delete return
81 *
82 * RETURN:      Status
83 *
84 * DESCRIPTION: Execute a control method or return the current value of an
85 *              ACPI namespace object.
86 *
87 * MUTEX:       Locks interpreter
88 *
89 ******************************************************************************/
90
91ACPI_STATUS
92AcpiNsEvaluate (
93    ACPI_EVALUATE_INFO      *Info)
94{
95    ACPI_STATUS             Status;
96    ACPI_NAMESPACE_NODE     *Node;
97
98
99    ACPI_FUNCTION_TRACE (NsEvaluate);
100
101
102    if (!Info)
103    {
104        return_ACPI_STATUS (AE_BAD_PARAMETER);
105    }
106
107    /* Initialize the return value to an invalid object */
108
109    Info->ReturnObject = NULL;
110    Info->ParamCount = 0;
111
112    /*
113     * Get the actual namespace node for the target object. Handles these cases:
114     *
115     * 1) Null node, Pathname (absolute path)
116     * 2) Node, Pathname (path relative to Node)
117     * 3) Node, Null Pathname
118     */
119    Status = AcpiNsGetNode (Info->PrefixNode, Info->Pathname,
120                ACPI_NS_NO_UPSEARCH, &Info->ResolvedNode);
121    if (ACPI_FAILURE (Status))
122    {
123        return_ACPI_STATUS (Status);
124    }
125
126    /*
127     * For a method alias, we must grab the actual method node so that proper
128     * scoping context will be established before execution.
129     */
130    if (AcpiNsGetType (Info->ResolvedNode) == ACPI_TYPE_LOCAL_METHOD_ALIAS)
131    {
132        Info->ResolvedNode =
133            ACPI_CAST_PTR (ACPI_NAMESPACE_NODE, Info->ResolvedNode->Object);
134    }
135
136    ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, "%s [%p] Value %p\n", Info->Pathname,
137        Info->ResolvedNode, AcpiNsGetAttachedObject (Info->ResolvedNode)));
138
139    Node = Info->ResolvedNode;
140
141    /*
142     * Two major cases here:
143     *
144     * 1) The object is a control method -- execute it
145     * 2) The object is not a method -- just return it's current value
146     */
147    if (AcpiNsGetType (Info->ResolvedNode) == ACPI_TYPE_METHOD)
148    {
149        /*
150         * 1) Object is a control method - execute it
151         */
152
153        /* Verify that there is a method object associated with this node */
154
155        Info->ObjDesc = AcpiNsGetAttachedObject (Info->ResolvedNode);
156        if (!Info->ObjDesc)
157        {
158            ACPI_ERROR ((AE_INFO, "Control method has no attached sub-object"));
159            return_ACPI_STATUS (AE_NULL_OBJECT);
160        }
161
162        /* Count the number of arguments being passed to the method */
163
164        if (Info->Parameters)
165        {
166            while (Info->Parameters[Info->ParamCount])
167            {
168                if (Info->ParamCount > ACPI_METHOD_MAX_ARG)
169                {
170                    return_ACPI_STATUS (AE_LIMIT);
171                }
172                Info->ParamCount++;
173            }
174        }
175
176        ACPI_DUMP_PATHNAME (Info->ResolvedNode, "ACPI: Execute Method",
177            ACPI_LV_INFO, _COMPONENT);
178
179        ACPI_DEBUG_PRINT ((ACPI_DB_EXEC,
180            "Method at AML address %p Length %X\n",
181            Info->ObjDesc->Method.AmlStart + 1,
182            Info->ObjDesc->Method.AmlLength - 1));
183
184        /*
185         * Any namespace deletion must acquire both the namespace and
186         * interpreter locks to ensure that no thread is using the portion of
187         * the namespace that is being deleted.
188         *
189         * Execute the method via the interpreter. The interpreter is locked
190         * here before calling into the AML parser
191         */
192        AcpiExEnterInterpreter ();
193        Status = AcpiPsExecuteMethod (Info);
194        AcpiExExitInterpreter ();
195    }
196    else
197    {
198        /*
199         * 2) Object is not a method, return its current value
200         *
201         * Disallow certain object types. For these, "evaluation" is undefined.
202         */
203        switch (Info->ResolvedNode->Type)
204        {
205        case ACPI_TYPE_DEVICE:
206        case ACPI_TYPE_EVENT:
207        case ACPI_TYPE_MUTEX:
208        case ACPI_TYPE_REGION:
209        case ACPI_TYPE_THERMAL:
210        case ACPI_TYPE_LOCAL_SCOPE:
211
212            ACPI_ERROR ((AE_INFO,
213                "[%4.4s] Evaluation of object type [%s] is not supported",
214                Info->ResolvedNode->Name.Ascii,
215                AcpiUtGetTypeName (Info->ResolvedNode->Type)));
216
217            return_ACPI_STATUS (AE_TYPE);
218
219        default:
220            break;
221        }
222
223        /*
224         * Objects require additional resolution steps (e.g., the Node may be
225         * a field that must be read, etc.) -- we can't just grab the object
226         * out of the node.
227         *
228         * Use ResolveNodeToValue() to get the associated value.
229         *
230         * NOTE: we can get away with passing in NULL for a walk state because
231         * ResolvedNode is guaranteed to not be a reference to either a method
232         * local or a method argument (because this interface is never called
233         * from a running method.)
234         *
235         * Even though we do not directly invoke the interpreter for object
236         * resolution, we must lock it because we could access an opregion.
237         * The opregion access code assumes that the interpreter is locked.
238         */
239        AcpiExEnterInterpreter ();
240
241        /* Function has a strange interface */
242
243        Status = AcpiExResolveNodeToValue (&Info->ResolvedNode, NULL);
244        AcpiExExitInterpreter ();
245
246        /*
247         * If AcpiExResolveNodeToValue() succeeded, the return value was placed
248         * in ResolvedNode.
249         */
250        if (ACPI_SUCCESS (Status))
251        {
252            Status = AE_CTRL_RETURN_VALUE;
253            Info->ReturnObject =
254                ACPI_CAST_PTR (ACPI_OPERAND_OBJECT, Info->ResolvedNode);
255
256            ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, "Returning object %p [%s]\n",
257                Info->ReturnObject,
258                AcpiUtGetObjectTypeName (Info->ReturnObject)));
259        }
260    }
261
262    /*
263     * Check input argument count against the ASL-defined count for a method.
264     * Also check predefined names: argument count and return value against
265     * the ACPI specification. Some incorrect return value types are repaired.
266     */
267    (void) AcpiNsCheckPredefinedNames (Node, Info->ParamCount,
268                Status, &Info->ReturnObject);
269
270    /* Check if there is a return value that must be dealt with */
271
272    if (Status == AE_CTRL_RETURN_VALUE)
273    {
274        /* If caller does not want the return value, delete it */
275
276        if (Info->Flags & ACPI_IGNORE_RETURN_VALUE)
277        {
278            AcpiUtRemoveReference (Info->ReturnObject);
279            Info->ReturnObject = NULL;
280        }
281
282        /* Map AE_CTRL_RETURN_VALUE to AE_OK, we are done with it */
283
284        Status = AE_OK;
285    }
286
287    ACPI_DEBUG_PRINT ((ACPI_DB_NAMES,
288        "*** Completed evaluation of object %s ***\n", Info->Pathname));
289
290    /*
291     * Namespace was unlocked by the handling AcpiNs* function, so we
292     * just return
293     */
294    return_ACPI_STATUS (Status);
295}
296
297
298/*******************************************************************************
299 *
300 * FUNCTION:    AcpiNsExecModuleCodeList
301 *
302 * PARAMETERS:  None
303 *
304 * RETURN:      None. Exceptions during method execution are ignored, since
305 *              we cannot abort a table load.
306 *
307 * DESCRIPTION: Execute all elements of the global module-level code list.
308 *              Each element is executed as a single control method.
309 *
310 ******************************************************************************/
311
312void
313AcpiNsExecModuleCodeList (
314    void)
315{
316    ACPI_OPERAND_OBJECT     *Prev;
317    ACPI_OPERAND_OBJECT     *Next;
318    ACPI_EVALUATE_INFO      *Info;
319    UINT32                  MethodCount = 0;
320
321
322    ACPI_FUNCTION_TRACE (NsExecModuleCodeList);
323
324
325    /* Exit now if the list is empty */
326
327    Next = AcpiGbl_ModuleCodeList;
328    if (!Next)
329    {
330        return_VOID;
331    }
332
333    /* Allocate the evaluation information block */
334
335    Info = ACPI_ALLOCATE (sizeof (ACPI_EVALUATE_INFO));
336    if (!Info)
337    {
338        return_VOID;
339    }
340
341    /* Walk the list, executing each "method" */
342
343    while (Next)
344    {
345        Prev = Next;
346        Next = Next->Method.Mutex;
347
348        /* Clear the link field and execute the method */
349
350        Prev->Method.Mutex = NULL;
351        AcpiNsExecModuleCode (Prev, Info);
352        MethodCount++;
353
354        /* Delete the (temporary) method object */
355
356        AcpiUtRemoveReference (Prev);
357    }
358
359    ACPI_INFO ((AE_INFO,
360        "Executed %u blocks of module-level executable AML code",
361        MethodCount));
362
363    ACPI_FREE (Info);
364    AcpiGbl_ModuleCodeList = NULL;
365    return_VOID;
366}
367
368
369/*******************************************************************************
370 *
371 * FUNCTION:    AcpiNsExecModuleCode
372 *
373 * PARAMETERS:  MethodObj           - Object container for the module-level code
374 *              Info                - Info block for method evaluation
375 *
376 * RETURN:      None. Exceptions during method execution are ignored, since
377 *              we cannot abort a table load.
378 *
379 * DESCRIPTION: Execute a control method containing a block of module-level
380 *              executable AML code. The control method is temporarily
381 *              installed to the root node, then evaluated.
382 *
383 ******************************************************************************/
384
385static void
386AcpiNsExecModuleCode (
387    ACPI_OPERAND_OBJECT     *MethodObj,
388    ACPI_EVALUATE_INFO      *Info)
389{
390    ACPI_OPERAND_OBJECT     *ParentObj;
391    ACPI_NAMESPACE_NODE     *ParentNode;
392    ACPI_OBJECT_TYPE        Type;
393    ACPI_STATUS             Status;
394
395
396    ACPI_FUNCTION_TRACE (NsExecModuleCode);
397
398
399    /*
400     * Get the parent node. We cheat by using the NextObject field
401     * of the method object descriptor.
402     */
403    ParentNode = ACPI_CAST_PTR (ACPI_NAMESPACE_NODE,
404                    MethodObj->Method.NextObject);
405    Type = AcpiNsGetType (ParentNode);
406
407    /*
408     * Get the region handler and save it in the method object. We may need
409     * this if an operation region declaration causes a _REG method to be run.
410     *
411     * We can't do this in AcpiPsLinkModuleCode because
412     * AcpiGbl_RootNode->Object is NULL at PASS1.
413     */
414    if ((Type == ACPI_TYPE_DEVICE) && ParentNode->Object)
415    {
416        MethodObj->Method.Dispatch.Handler =
417            ParentNode->Object->Device.Handler;
418    }
419
420    /* Must clear NextObject (AcpiNsAttachObject needs the field) */
421
422    MethodObj->Method.NextObject = NULL;
423
424    /* Initialize the evaluation information block */
425
426    ACPI_MEMSET (Info, 0, sizeof (ACPI_EVALUATE_INFO));
427    Info->PrefixNode = ParentNode;
428
429    /*
430     * Get the currently attached parent object. Add a reference, because the
431     * ref count will be decreased when the method object is installed to
432     * the parent node.
433     */
434    ParentObj = AcpiNsGetAttachedObject (ParentNode);
435    if (ParentObj)
436    {
437        AcpiUtAddReference (ParentObj);
438    }
439
440    /* Install the method (module-level code) in the parent node */
441
442    Status = AcpiNsAttachObject (ParentNode, MethodObj,
443                ACPI_TYPE_METHOD);
444    if (ACPI_FAILURE (Status))
445    {
446        goto Exit;
447    }
448
449    /* Execute the parent node as a control method */
450
451    Status = AcpiNsEvaluate (Info);
452
453    ACPI_DEBUG_PRINT ((ACPI_DB_INIT, "Executed module-level code at %p\n",
454        MethodObj->Method.AmlStart));
455
456    /* Delete a possible implicit return value (in slack mode) */
457
458    if (Info->ReturnObject)
459    {
460        AcpiUtRemoveReference (Info->ReturnObject);
461    }
462
463    /* Detach the temporary method object */
464
465    AcpiNsDetachObject (ParentNode);
466
467    /* Restore the original parent object */
468
469    if (ParentObj)
470    {
471        Status = AcpiNsAttachObject (ParentNode, ParentObj, Type);
472    }
473    else
474    {
475        ParentNode->Type = (UINT8) Type;
476    }
477
478Exit:
479    if (ParentObj)
480    {
481        AcpiUtRemoveReference (ParentObj);
482    }
483    return_VOID;
484}
485
486