167754Smsmith/*******************************************************************************
267754Smsmith *
367754Smsmith * Module Name: dsutils - Dispatcher utilities
467754Smsmith *
567754Smsmith ******************************************************************************/
667754Smsmith
7217365Sjkim/*
8281075Sdim * Copyright (C) 2000 - 2015, Intel Corp.
970243Smsmith * All rights reserved.
1067754Smsmith *
11217365Sjkim * Redistribution and use in source and binary forms, with or without
12217365Sjkim * modification, are permitted provided that the following conditions
13217365Sjkim * are met:
14217365Sjkim * 1. Redistributions of source code must retain the above copyright
15217365Sjkim *    notice, this list of conditions, and the following disclaimer,
16217365Sjkim *    without modification.
17217365Sjkim * 2. Redistributions in binary form must reproduce at minimum a disclaimer
18217365Sjkim *    substantially similar to the "NO WARRANTY" disclaimer below
19217365Sjkim *    ("Disclaimer") and any redistribution must be conditioned upon
20217365Sjkim *    including a substantially similar Disclaimer requirement for further
21217365Sjkim *    binary redistribution.
22217365Sjkim * 3. Neither the names of the above-listed copyright holders nor the names
23217365Sjkim *    of any contributors may be used to endorse or promote products derived
24217365Sjkim *    from this software without specific prior written permission.
2567754Smsmith *
26217365Sjkim * Alternatively, this software may be distributed under the terms of the
27217365Sjkim * GNU General Public License ("GPL") version 2 as published by the Free
28217365Sjkim * Software Foundation.
2967754Smsmith *
30217365Sjkim * NO WARRANTY
31217365Sjkim * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32217365Sjkim * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33217365Sjkim * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
34217365Sjkim * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
35217365Sjkim * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36217365Sjkim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37217365Sjkim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38217365Sjkim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39217365Sjkim * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
40217365Sjkim * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41217365Sjkim * POSSIBILITY OF SUCH DAMAGES.
42217365Sjkim */
4367754Smsmith
44193341Sjkim#include <contrib/dev/acpica/include/acpi.h>
45193341Sjkim#include <contrib/dev/acpica/include/accommon.h>
46193341Sjkim#include <contrib/dev/acpica/include/acparser.h>
47193341Sjkim#include <contrib/dev/acpica/include/amlcode.h>
48193341Sjkim#include <contrib/dev/acpica/include/acdispat.h>
49193341Sjkim#include <contrib/dev/acpica/include/acinterp.h>
50193341Sjkim#include <contrib/dev/acpica/include/acnamesp.h>
51193341Sjkim#include <contrib/dev/acpica/include/acdebug.h>
5267754Smsmith
5377424Smsmith#define _COMPONENT          ACPI_DISPATCHER
5491116Smsmith        ACPI_MODULE_NAME    ("dsutils")
5567754Smsmith
56123315Snjl
57151937Sjkim/*******************************************************************************
58151937Sjkim *
59151937Sjkim * FUNCTION:    AcpiDsClearImplicitReturn
60151937Sjkim *
61151937Sjkim * PARAMETERS:  WalkState           - Current State
62151937Sjkim *
63151937Sjkim * RETURN:      None.
64151937Sjkim *
65241973Sjkim * DESCRIPTION: Clear and remove a reference on an implicit return value. Used
66151937Sjkim *              to delete "stale" return values (if enabled, the return value
67151937Sjkim *              from every operator is saved at least momentarily, in case the
68151937Sjkim *              parent method exits.)
69151937Sjkim *
70151937Sjkim ******************************************************************************/
71151937Sjkim
72151937Sjkimvoid
73151937SjkimAcpiDsClearImplicitReturn (
74151937Sjkim    ACPI_WALK_STATE         *WalkState)
75151937Sjkim{
76167802Sjkim    ACPI_FUNCTION_NAME (DsClearImplicitReturn);
77151937Sjkim
78151937Sjkim
79151937Sjkim    /*
80151937Sjkim     * Slack must be enabled for this feature
81151937Sjkim     */
82151937Sjkim    if (!AcpiGbl_EnableInterpreterSlack)
83151937Sjkim    {
84151937Sjkim        return;
85151937Sjkim    }
86151937Sjkim
87151937Sjkim    if (WalkState->ImplicitReturnObj)
88151937Sjkim    {
89151937Sjkim        /*
90151937Sjkim         * Delete any "stale" implicit return. However, in
91151937Sjkim         * complex statements, the implicit return value can be
92151937Sjkim         * bubbled up several levels.
93151937Sjkim         */
94151937Sjkim        ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
95151937Sjkim            "Removing reference on stale implicit return obj %p\n",
96151937Sjkim            WalkState->ImplicitReturnObj));
97151937Sjkim
98151937Sjkim        AcpiUtRemoveReference (WalkState->ImplicitReturnObj);
99151937Sjkim        WalkState->ImplicitReturnObj = NULL;
100151937Sjkim    }
101151937Sjkim}
102151937Sjkim
103151937Sjkim
104100966Siwasaki#ifndef ACPI_NO_METHOD_EXECUTION
105151937Sjkim/*******************************************************************************
106151937Sjkim *
107151937Sjkim * FUNCTION:    AcpiDsDoImplicitReturn
108151937Sjkim *
109151937Sjkim * PARAMETERS:  ReturnDesc          - The return value
110151937Sjkim *              WalkState           - Current State
111151937Sjkim *              AddReference        - True if a reference should be added to the
112151937Sjkim *                                    return object
113151937Sjkim *
114151937Sjkim * RETURN:      TRUE if implicit return enabled, FALSE otherwise
115151937Sjkim *
116151937Sjkim * DESCRIPTION: Implements the optional "implicit return".  We save the result
117151937Sjkim *              of every ASL operator and control method invocation in case the
118241973Sjkim *              parent method exit. Before storing a new return value, we
119151937Sjkim *              delete the previous return value.
120151937Sjkim *
121151937Sjkim ******************************************************************************/
12267754Smsmith
123151937SjkimBOOLEAN
124151937SjkimAcpiDsDoImplicitReturn (
125151937Sjkim    ACPI_OPERAND_OBJECT     *ReturnDesc,
126151937Sjkim    ACPI_WALK_STATE         *WalkState,
127151937Sjkim    BOOLEAN                 AddReference)
128151937Sjkim{
129167802Sjkim    ACPI_FUNCTION_NAME (DsDoImplicitReturn);
130151937Sjkim
131151937Sjkim
132151937Sjkim    /*
133151937Sjkim     * Slack must be enabled for this feature, and we must
134151937Sjkim     * have a valid return object
135151937Sjkim     */
136151937Sjkim    if ((!AcpiGbl_EnableInterpreterSlack) ||
137151937Sjkim        (!ReturnDesc))
138151937Sjkim    {
139151937Sjkim        return (FALSE);
140151937Sjkim    }
141151937Sjkim
142151937Sjkim    ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
143151937Sjkim            "Result %p will be implicitly returned; Prev=%p\n",
144151937Sjkim            ReturnDesc,
145151937Sjkim            WalkState->ImplicitReturnObj));
146151937Sjkim
147151937Sjkim    /*
148151937Sjkim     * Delete any "stale" implicit return value first. However, in
149151937Sjkim     * complex statements, the implicit return value can be
150151937Sjkim     * bubbled up several levels, so we don't clear the value if it
151151937Sjkim     * is the same as the ReturnDesc.
152151937Sjkim     */
153151937Sjkim    if (WalkState->ImplicitReturnObj)
154151937Sjkim    {
155151937Sjkim        if (WalkState->ImplicitReturnObj == ReturnDesc)
156151937Sjkim        {
157151937Sjkim            return (TRUE);
158151937Sjkim        }
159151937Sjkim        AcpiDsClearImplicitReturn (WalkState);
160151937Sjkim    }
161151937Sjkim
162151937Sjkim    /* Save the implicit return value, add a reference if requested */
163151937Sjkim
164151937Sjkim    WalkState->ImplicitReturnObj = ReturnDesc;
165151937Sjkim    if (AddReference)
166151937Sjkim    {
167151937Sjkim        AcpiUtAddReference (ReturnDesc);
168151937Sjkim    }
169151937Sjkim
170151937Sjkim    return (TRUE);
171151937Sjkim}
172151937Sjkim
173151937Sjkim
17467754Smsmith/*******************************************************************************
17567754Smsmith *
17667754Smsmith * FUNCTION:    AcpiDsIsResultUsed
17767754Smsmith *
178138287Smarks * PARAMETERS:  Op                  - Current Op
179138287Smarks *              WalkState           - Current State
18067754Smsmith *
181138287Smarks * RETURN:      TRUE if result is used, FALSE otherwise
18267754Smsmith *
18367754Smsmith * DESCRIPTION: Check if a result object will be used by the parent
18467754Smsmith *
18567754Smsmith ******************************************************************************/
18667754Smsmith
18767754SmsmithBOOLEAN
18867754SmsmithAcpiDsIsResultUsed (
18967754Smsmith    ACPI_PARSE_OBJECT       *Op,
19067754Smsmith    ACPI_WALK_STATE         *WalkState)
19167754Smsmith{
19283174Smsmith    const ACPI_OPCODE_INFO  *ParentInfo;
19367754Smsmith
194167802Sjkim    ACPI_FUNCTION_TRACE_PTR (DsIsResultUsed, Op);
19567754Smsmith
19667754Smsmith
19767754Smsmith    /* Must have both an Op and a Result Object */
19867754Smsmith
19967754Smsmith    if (!Op)
20067754Smsmith    {
201167802Sjkim        ACPI_ERROR ((AE_INFO, "Null Op"));
202246849Sjkim        return_UINT8 (TRUE);
20367754Smsmith    }
20467754Smsmith
20567754Smsmith    /*
206151937Sjkim     * We know that this operator is not a
207151937Sjkim     * Return() operator (would not come here.) The following code is the
208151937Sjkim     * optional support for a so-called "implicit return". Some AML code
209151937Sjkim     * assumes that the last value of the method is "implicitly" returned
210151937Sjkim     * to the caller. Just save the last result as the return value.
211151937Sjkim     * NOTE: this is optional because the ASL language does not actually
212151937Sjkim     * support this behavior.
21367754Smsmith     */
214151937Sjkim    (void) AcpiDsDoImplicitReturn (WalkState->ResultObj, WalkState, TRUE);
215151937Sjkim
216151937Sjkim    /*
217151937Sjkim     * Now determine if the parent will use the result
218151937Sjkim     *
219151937Sjkim     * If there is no parent, or the parent is a ScopeOp, we are executing
220151937Sjkim     * at the method level. An executing method typically has no parent,
221241973Sjkim     * since each method is parsed separately. A method invoked externally
222151937Sjkim     * via ExecuteControlMethod has a ScopeOp as the parent.
223151937Sjkim     */
224151937Sjkim    if ((!Op->Common.Parent) ||
225151937Sjkim        (Op->Common.Parent->Common.AmlOpcode == AML_SCOPE_OP))
22667754Smsmith    {
227138287Smarks        /* No parent, the return value cannot possibly be used */
228138287Smarks
229151937Sjkim        ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
230151937Sjkim            "At Method level, result of [%s] not used\n",
231151937Sjkim            AcpiPsGetOpcodeName (Op->Common.AmlOpcode)));
232246849Sjkim        return_UINT8 (FALSE);
23367754Smsmith    }
23467754Smsmith
235138287Smarks    /* Get info on the parent. The RootOp is AML_SCOPE */
236138287Smarks
23799679Siwasaki    ParentInfo = AcpiPsGetOpcodeInfo (Op->Common.Parent->Common.AmlOpcode);
23885756Smsmith    if (ParentInfo->Class == AML_CLASS_UNKNOWN)
23967754Smsmith    {
240167802Sjkim        ACPI_ERROR ((AE_INFO,
241167802Sjkim            "Unknown parent opcode Op=%p", Op));
242246849Sjkim        return_UINT8 (FALSE);
24367754Smsmith    }
24467754Smsmith
24567754Smsmith    /*
246241973Sjkim     * Decide what to do with the result based on the parent. If
24767754Smsmith     * the parent opcode will not use the result, delete the object.
24867754Smsmith     * Otherwise leave it as is, it will be deleted when it is used
24967754Smsmith     * as an operand later.
25067754Smsmith     */
25185756Smsmith    switch (ParentInfo->Class)
25267754Smsmith    {
25387031Smsmith    case AML_CLASS_CONTROL:
25467754Smsmith
25599679Siwasaki        switch (Op->Common.Parent->Common.AmlOpcode)
25667754Smsmith        {
25767754Smsmith        case AML_RETURN_OP:
25867754Smsmith
25967754Smsmith            /* Never delete the return value associated with a return opcode */
26067754Smsmith
26187031Smsmith            goto ResultUsed;
26267754Smsmith
26367754Smsmith        case AML_IF_OP:
26467754Smsmith        case AML_WHILE_OP:
26569450Smsmith            /*
26669450Smsmith             * If we are executing the predicate AND this is the predicate op,
26787031Smsmith             * we will use the return value
26867754Smsmith             */
26991116Smsmith            if ((WalkState->ControlState->Common.State == ACPI_CONTROL_PREDICATE_EXECUTING) &&
27067754Smsmith                (WalkState->ControlState->Control.PredicateOp == Op))
27167754Smsmith            {
27287031Smsmith                goto ResultUsed;
27367754Smsmith            }
27499679Siwasaki            break;
27599679Siwasaki
27699679Siwasaki        default:
277250838Sjkim
27899679Siwasaki            /* Ignore other control opcodes */
279250838Sjkim
28099679Siwasaki            break;
28167754Smsmith        }
28267754Smsmith
28387031Smsmith        /* The general control opcode returns no result */
28469450Smsmith
28587031Smsmith        goto ResultNotUsed;
28667754Smsmith
28785756Smsmith    case AML_CLASS_CREATE:
28870243Smsmith        /*
28969746Smsmith         * These opcodes allow TermArg(s) as operands and therefore
290241973Sjkim         * the operands can be method calls. The result is used.
29169746Smsmith         */
29287031Smsmith        goto ResultUsed;
29387031Smsmith
29487031Smsmith    case AML_CLASS_NAMED_OBJECT:
29587031Smsmith
29699679Siwasaki        if ((Op->Common.Parent->Common.AmlOpcode == AML_REGION_OP)       ||
29799679Siwasaki            (Op->Common.Parent->Common.AmlOpcode == AML_DATA_REGION_OP)  ||
29899679Siwasaki            (Op->Common.Parent->Common.AmlOpcode == AML_PACKAGE_OP)      ||
29999679Siwasaki            (Op->Common.Parent->Common.AmlOpcode == AML_VAR_PACKAGE_OP)  ||
30099679Siwasaki            (Op->Common.Parent->Common.AmlOpcode == AML_BUFFER_OP)       ||
301193267Sjkim            (Op->Common.Parent->Common.AmlOpcode == AML_INT_EVAL_SUBTREE_OP) ||
302193267Sjkim            (Op->Common.Parent->Common.AmlOpcode == AML_BANK_FIELD_OP))
30369746Smsmith        {
30487031Smsmith            /*
30587031Smsmith             * These opcodes allow TermArg(s) as operands and therefore
306241973Sjkim             * the operands can be method calls. The result is used.
30787031Smsmith             */
30887031Smsmith            goto ResultUsed;
30969746Smsmith        }
31069746Smsmith
31187031Smsmith        goto ResultNotUsed;
31267754Smsmith
31367754Smsmith    default:
31499146Siwasaki        /*
31599146Siwasaki         * In all other cases. the parent will actually use the return
31699146Siwasaki         * object, so keep it.
31799146Siwasaki         */
31887031Smsmith        goto ResultUsed;
31967754Smsmith    }
32067754Smsmith
32187031Smsmith
32287031SmsmithResultUsed:
323151937Sjkim    ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
324151937Sjkim        "Result of [%s] used by Parent [%s] Op=%p\n",
325151937Sjkim        AcpiPsGetOpcodeName (Op->Common.AmlOpcode),
326151937Sjkim        AcpiPsGetOpcodeName (Op->Common.Parent->Common.AmlOpcode), Op));
32787031Smsmith
328246849Sjkim    return_UINT8 (TRUE);
32987031Smsmith
33087031Smsmith
33187031SmsmithResultNotUsed:
332151937Sjkim    ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
333151937Sjkim        "Result of [%s] not used by Parent [%s] Op=%p\n",
334151937Sjkim        AcpiPsGetOpcodeName (Op->Common.AmlOpcode),
335151937Sjkim        AcpiPsGetOpcodeName (Op->Common.Parent->Common.AmlOpcode), Op));
33687031Smsmith
337246849Sjkim    return_UINT8 (FALSE);
33867754Smsmith}
33967754Smsmith
34067754Smsmith
34167754Smsmith/*******************************************************************************
34267754Smsmith *
34367754Smsmith * FUNCTION:    AcpiDsDeleteResultIfNotUsed
34467754Smsmith *
345138287Smarks * PARAMETERS:  Op              - Current parse Op
346138287Smarks *              ResultObj       - Result of the operation
347138287Smarks *              WalkState       - Current state
34867754Smsmith *
34967754Smsmith * RETURN:      Status
35067754Smsmith *
351241973Sjkim * DESCRIPTION: Used after interpretation of an opcode. If there is an internal
35267754Smsmith *              result descriptor, check if the parent opcode will actually use
353241973Sjkim *              this result. If not, delete the result now so that it will
35467754Smsmith *              not become orphaned.
35567754Smsmith *
35667754Smsmith ******************************************************************************/
35767754Smsmith
35867754Smsmithvoid
35967754SmsmithAcpiDsDeleteResultIfNotUsed (
36067754Smsmith    ACPI_PARSE_OBJECT       *Op,
36167754Smsmith    ACPI_OPERAND_OBJECT     *ResultObj,
36267754Smsmith    ACPI_WALK_STATE         *WalkState)
36367754Smsmith{
36467754Smsmith    ACPI_OPERAND_OBJECT     *ObjDesc;
36567754Smsmith    ACPI_STATUS             Status;
36667754Smsmith
36767754Smsmith
368167802Sjkim    ACPI_FUNCTION_TRACE_PTR (DsDeleteResultIfNotUsed, ResultObj);
36967754Smsmith
37067754Smsmith
37167754Smsmith    if (!Op)
37267754Smsmith    {
373167802Sjkim        ACPI_ERROR ((AE_INFO, "Null Op"));
37467754Smsmith        return_VOID;
37567754Smsmith    }
37667754Smsmith
37767754Smsmith    if (!ResultObj)
37867754Smsmith    {
37967754Smsmith        return_VOID;
38067754Smsmith    }
38167754Smsmith
38267754Smsmith    if (!AcpiDsIsResultUsed (Op, WalkState))
38367754Smsmith    {
384151937Sjkim        /* Must pop the result stack (ObjDesc should be equal to ResultObj) */
385151937Sjkim
38669746Smsmith        Status = AcpiDsResultPop (&ObjDesc, WalkState);
38767754Smsmith        if (ACPI_SUCCESS (Status))
38867754Smsmith        {
38977424Smsmith            AcpiUtRemoveReference (ResultObj);
39067754Smsmith        }
39167754Smsmith    }
39267754Smsmith
39367754Smsmith    return_VOID;
39467754Smsmith}
39567754Smsmith
39667754Smsmith
39767754Smsmith/*******************************************************************************
39867754Smsmith *
399100966Siwasaki * FUNCTION:    AcpiDsResolveOperands
400100966Siwasaki *
401100966Siwasaki * PARAMETERS:  WalkState           - Current walk state with operands on stack
402100966Siwasaki *
403100966Siwasaki * RETURN:      Status
404100966Siwasaki *
405241973Sjkim * DESCRIPTION: Resolve all operands to their values. Used to prepare
406100966Siwasaki *              arguments to a control method invocation (a call from one
407100966Siwasaki *              method to another.)
408100966Siwasaki *
409100966Siwasaki ******************************************************************************/
410100966Siwasaki
411100966SiwasakiACPI_STATUS
412100966SiwasakiAcpiDsResolveOperands (
413100966Siwasaki    ACPI_WALK_STATE         *WalkState)
414100966Siwasaki{
415100966Siwasaki    UINT32                  i;
416100966Siwasaki    ACPI_STATUS             Status = AE_OK;
417100966Siwasaki
418100966Siwasaki
419167802Sjkim    ACPI_FUNCTION_TRACE_PTR (DsResolveOperands, WalkState);
420100966Siwasaki
421100966Siwasaki
422100966Siwasaki    /*
423100966Siwasaki     * Attempt to resolve each of the valid operands
424241973Sjkim     * Method arguments are passed by reference, not by value. This means
425126372Snjl     * that the actual objects are passed, not copies of the objects.
426100966Siwasaki     */
427100966Siwasaki    for (i = 0; i < WalkState->NumOperands; i++)
428100966Siwasaki    {
429100966Siwasaki        Status = AcpiExResolveToValue (&WalkState->Operands[i], WalkState);
430100966Siwasaki        if (ACPI_FAILURE (Status))
431100966Siwasaki        {
432100966Siwasaki            break;
433100966Siwasaki        }
434100966Siwasaki    }
435100966Siwasaki
436100966Siwasaki    return_ACPI_STATUS (Status);
437100966Siwasaki}
438107325Siwasaki
439107325Siwasaki
440107325Siwasaki/*******************************************************************************
441107325Siwasaki *
442107325Siwasaki * FUNCTION:    AcpiDsClearOperands
443107325Siwasaki *
444107325Siwasaki * PARAMETERS:  WalkState           - Current walk state with operands on stack
445107325Siwasaki *
446107325Siwasaki * RETURN:      None
447107325Siwasaki *
448107325Siwasaki * DESCRIPTION: Clear all operands on the current walk state operand stack.
449107325Siwasaki *
450107325Siwasaki ******************************************************************************/
451107325Siwasaki
452107325Siwasakivoid
453107325SiwasakiAcpiDsClearOperands (
454107325Siwasaki    ACPI_WALK_STATE         *WalkState)
455107325Siwasaki{
456107325Siwasaki    UINT32                  i;
457107325Siwasaki
458107325Siwasaki
459167802Sjkim    ACPI_FUNCTION_TRACE_PTR (DsClearOperands, WalkState);
460107325Siwasaki
461107325Siwasaki
462151937Sjkim    /* Remove a reference on each operand on the stack */
463151937Sjkim
464107325Siwasaki    for (i = 0; i < WalkState->NumOperands; i++)
465107325Siwasaki    {
466107325Siwasaki        /*
467107325Siwasaki         * Remove a reference to all operands, including both
468107325Siwasaki         * "Arguments" and "Targets".
469107325Siwasaki         */
470107325Siwasaki        AcpiUtRemoveReference (WalkState->Operands[i]);
471107325Siwasaki        WalkState->Operands[i] = NULL;
472107325Siwasaki    }
473107325Siwasaki
474107325Siwasaki    WalkState->NumOperands = 0;
475107325Siwasaki    return_VOID;
476107325Siwasaki}
477100966Siwasaki#endif
478100966Siwasaki
479100966Siwasaki
480100966Siwasaki/*******************************************************************************
481100966Siwasaki *
48267754Smsmith * FUNCTION:    AcpiDsCreateOperand
48367754Smsmith *
484138287Smarks * PARAMETERS:  WalkState       - Current walk state
485138287Smarks *              Arg             - Parse object for the argument
486138287Smarks *              ArgIndex        - Which argument (zero based)
48767754Smsmith *
48867754Smsmith * RETURN:      Status
48967754Smsmith *
49067754Smsmith * DESCRIPTION: Translate a parse tree object that is an argument to an AML
491241973Sjkim *              opcode to the equivalent interpreter object. This may include
49267754Smsmith *              looking up a name or entering a new name into the internal
49367754Smsmith *              namespace.
49467754Smsmith *
49567754Smsmith ******************************************************************************/
49667754Smsmith
49767754SmsmithACPI_STATUS
49867754SmsmithAcpiDsCreateOperand (
49967754Smsmith    ACPI_WALK_STATE         *WalkState,
50069746Smsmith    ACPI_PARSE_OBJECT       *Arg,
50169746Smsmith    UINT32                  ArgIndex)
50267754Smsmith{
50367754Smsmith    ACPI_STATUS             Status = AE_OK;
504114237Snjl    char                    *NameString;
50567754Smsmith    UINT32                  NameLength;
50667754Smsmith    ACPI_OPERAND_OBJECT     *ObjDesc;
50767754Smsmith    ACPI_PARSE_OBJECT       *ParentOp;
50867754Smsmith    UINT16                  Opcode;
50991116Smsmith    ACPI_INTERPRETER_MODE   InterpreterMode;
51083174Smsmith    const ACPI_OPCODE_INFO  *OpInfo;
51167754Smsmith
51267754Smsmith
513167802Sjkim    ACPI_FUNCTION_TRACE_PTR (DsCreateOperand, Arg);
51467754Smsmith
51567754Smsmith
51667754Smsmith    /* A valid name must be looked up in the namespace */
51767754Smsmith
51899679Siwasaki    if ((Arg->Common.AmlOpcode == AML_INT_NAMEPATH_OP) &&
519167802Sjkim        (Arg->Common.Value.String) &&
520167802Sjkim        !(Arg->Common.Flags & ACPI_PARSEOP_IN_STACK))
52167754Smsmith    {
52282367Smsmith        ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "Getting a name: Arg=%p\n", Arg));
52367754Smsmith
52467754Smsmith        /* Get the entire name string from the AML stream */
52567754Smsmith
52699679Siwasaki        Status = AcpiExGetNameString (ACPI_TYPE_ANY, Arg->Common.Value.Buffer,
52777424Smsmith                        &NameString, &NameLength);
52867754Smsmith
52967754Smsmith        if (ACPI_FAILURE (Status))
53067754Smsmith        {
53167754Smsmith            return_ACPI_STATUS (Status);
53267754Smsmith        }
53367754Smsmith
534151937Sjkim        /* All prefixes have been handled, and the name is in NameString */
53567754Smsmith
53667754Smsmith        /*
537241973Sjkim         * Special handling for BufferField declarations. This is a deferred
538123315Snjl         * opcode that unfortunately defines the field name as the last
539241973Sjkim         * parameter instead of the first. We get here when we are performing
540123315Snjl         * the deferred execution, so the actual name of the field is already
541241973Sjkim         * in the namespace. We don't want to attempt to look it up again
542123315Snjl         * because we may be executing in a different scope than where the
543123315Snjl         * actual opcode exists.
54467754Smsmith         */
545123315Snjl        if ((WalkState->DeferredNode) &&
546123315Snjl            (WalkState->DeferredNode->Type == ACPI_TYPE_BUFFER_FIELD) &&
547167802Sjkim            (ArgIndex == (UINT32) ((WalkState->Opcode == AML_CREATE_FIELD_OP) ? 3 : 2)))
54867754Smsmith        {
549151937Sjkim            ObjDesc = ACPI_CAST_PTR (
550151937Sjkim                        ACPI_OPERAND_OBJECT, WalkState->DeferredNode);
551123315Snjl            Status = AE_OK;
55267754Smsmith        }
553123315Snjl        else    /* All other opcodes */
55467754Smsmith        {
555123315Snjl            /*
556123315Snjl             * Differentiate between a namespace "create" operation
557123315Snjl             * versus a "lookup" operation (IMODE_LOAD_PASS2 vs.
558123315Snjl             * IMODE_EXECUTE) in order to support the creation of
559123315Snjl             * namespace objects during the execution of control methods.
560123315Snjl             */
561123315Snjl            ParentOp = Arg->Common.Parent;
562123315Snjl            OpInfo = AcpiPsGetOpcodeInfo (ParentOp->Common.AmlOpcode);
563123315Snjl            if ((OpInfo->Flags & AML_NSNODE) &&
564123315Snjl                (ParentOp->Common.AmlOpcode != AML_INT_METHODCALL_OP) &&
565123315Snjl                (ParentOp->Common.AmlOpcode != AML_REGION_OP) &&
566123315Snjl                (ParentOp->Common.AmlOpcode != AML_INT_NAMEPATH_OP))
567123315Snjl            {
568123315Snjl                /* Enter name into namespace if not found */
56967754Smsmith
570123315Snjl                InterpreterMode = ACPI_IMODE_LOAD_PASS2;
571123315Snjl            }
572123315Snjl            else
573123315Snjl            {
574123315Snjl                /* Return a failure if name not found */
57567754Smsmith
576123315Snjl                InterpreterMode = ACPI_IMODE_EXECUTE;
577123315Snjl            }
578123315Snjl
579123315Snjl            Status = AcpiNsLookup (WalkState->ScopeInfo, NameString,
580151937Sjkim                        ACPI_TYPE_ANY, InterpreterMode,
581151937Sjkim                        ACPI_NS_SEARCH_PARENT | ACPI_NS_DONT_OPEN_SCOPE,
582151937Sjkim                        WalkState,
583151937Sjkim                        ACPI_CAST_INDIRECT_PTR (ACPI_NAMESPACE_NODE, &ObjDesc));
584123315Snjl            /*
585123315Snjl             * The only case where we pass through (ignore) a NOT_FOUND
586123315Snjl             * error is for the CondRefOf opcode.
587123315Snjl             */
588123315Snjl            if (Status == AE_NOT_FOUND)
58967754Smsmith            {
590123315Snjl                if (ParentOp->Common.AmlOpcode == AML_COND_REF_OF_OP)
591123315Snjl                {
592123315Snjl                    /*
593123315Snjl                     * For the Conditional Reference op, it's OK if
594123315Snjl                     * the name is not found;  We just need a way to
595123315Snjl                     * indicate this to the interpreter, set the
596123315Snjl                     * object to the root
597123315Snjl                     */
598151937Sjkim                    ObjDesc = ACPI_CAST_PTR (
599151937Sjkim                                ACPI_OPERAND_OBJECT, AcpiGbl_RootNode);
600123315Snjl                    Status = AE_OK;
601123315Snjl                }
602281687Sjkim                else if (ParentOp->Common.AmlOpcode == AML_EXTERNAL_OP)
603281687Sjkim                {
604281687Sjkim                    /* TBD: May only be temporary */
605281687Sjkim
606281687Sjkim                    ObjDesc = AcpiUtCreateStringObject ((ACPI_SIZE) NameLength);
607281687Sjkim
608281687Sjkim                    ACPI_STRNCPY (ObjDesc->String.Pointer, NameString, NameLength);
609281687Sjkim                    Status = AE_OK;
610281687Sjkim                }
611123315Snjl                else
612123315Snjl                {
613123315Snjl                    /*
614123315Snjl                     * We just plain didn't find it -- which is a
615123315Snjl                     * very serious error at this point
616123315Snjl                     */
617123315Snjl                    Status = AE_AML_NAME_NOT_FOUND;
618123315Snjl                }
61967754Smsmith            }
62067754Smsmith
621123315Snjl            if (ACPI_FAILURE (Status))
62267754Smsmith            {
623167802Sjkim                ACPI_ERROR_NAMESPACE (NameString, Status);
62467754Smsmith            }
62567754Smsmith        }
62667754Smsmith
62791116Smsmith        /* Free the namestring created above */
62891116Smsmith
629167802Sjkim        ACPI_FREE (NameString);
63091116Smsmith
63167754Smsmith        /* Check status from the lookup */
63267754Smsmith
63367754Smsmith        if (ACPI_FAILURE (Status))
63467754Smsmith        {
63567754Smsmith            return_ACPI_STATUS (Status);
63667754Smsmith        }
63767754Smsmith
63867754Smsmith        /* Put the resulting object onto the current object stack */
63967754Smsmith
64067754Smsmith        Status = AcpiDsObjStackPush (ObjDesc, WalkState);
64167754Smsmith        if (ACPI_FAILURE (Status))
64267754Smsmith        {
64367754Smsmith            return_ACPI_STATUS (Status);
64467754Smsmith        }
64591116Smsmith        ACPI_DEBUGGER_EXEC (AcpiDbDisplayArgumentObject (ObjDesc, WalkState));
64667754Smsmith    }
64767754Smsmith    else
64867754Smsmith    {
64967754Smsmith        /* Check for null name case */
65067754Smsmith
651167802Sjkim        if ((Arg->Common.AmlOpcode == AML_INT_NAMEPATH_OP) &&
652167802Sjkim            !(Arg->Common.Flags & ACPI_PARSEOP_IN_STACK))
65367754Smsmith        {
65467754Smsmith            /*
65567754Smsmith             * If the name is null, this means that this is an
65667754Smsmith             * optional result parameter that was not specified
657241973Sjkim             * in the original ASL. Create a Zero Constant for a
658241973Sjkim             * placeholder. (Store to a constant is a Noop.)
65967754Smsmith             */
66067754Smsmith            Opcode = AML_ZERO_OP;       /* Has no arguments! */
66167754Smsmith
662151937Sjkim            ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
663151937Sjkim                "Null namepath: Arg=%p\n", Arg));
66467754Smsmith        }
66567754Smsmith        else
66667754Smsmith        {
66799679Siwasaki            Opcode = Arg->Common.AmlOpcode;
66867754Smsmith        }
66967754Smsmith
67087031Smsmith        /* Get the object type of the argument */
67167754Smsmith
67287031Smsmith        OpInfo = AcpiPsGetOpcodeInfo (Opcode);
673107325Siwasaki        if (OpInfo->ObjectType == ACPI_TYPE_INVALID)
67467754Smsmith        {
67567754Smsmith            return_ACPI_STATUS (AE_NOT_IMPLEMENTED);
67667754Smsmith        }
67767754Smsmith
678167802Sjkim        if ((OpInfo->Flags & AML_HAS_RETVAL) || (Arg->Common.Flags & ACPI_PARSEOP_IN_STACK))
67967754Smsmith        {
68082367Smsmith            ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
681151937Sjkim                "Argument previously created, already stacked\n"));
68267754Smsmith
68391116Smsmith            ACPI_DEBUGGER_EXEC (AcpiDbDisplayArgumentObject (
68491116Smsmith                WalkState->Operands [WalkState->NumOperands - 1], WalkState));
68567754Smsmith
68667754Smsmith            /*
68767754Smsmith             * Use value that was already previously returned
68867754Smsmith             * by the evaluation of this argument
68967754Smsmith             */
690167802Sjkim            Status = AcpiDsResultPop (&ObjDesc, WalkState);
69167754Smsmith            if (ACPI_FAILURE (Status))
69267754Smsmith            {
69367754Smsmith                /*
69467754Smsmith                 * Only error is underflow, and this indicates
69567754Smsmith                 * a missing or null operand!
69667754Smsmith                 */
697167802Sjkim                ACPI_EXCEPTION ((AE_INFO, Status,
698167802Sjkim                    "Missing or null operand"));
69967754Smsmith                return_ACPI_STATUS (Status);
70067754Smsmith            }
70167754Smsmith        }
70267754Smsmith        else
70367754Smsmith        {
70467754Smsmith            /* Create an ACPI_INTERNAL_OBJECT for the argument */
70567754Smsmith
70687031Smsmith            ObjDesc = AcpiUtCreateInternalObject (OpInfo->ObjectType);
70767754Smsmith            if (!ObjDesc)
70867754Smsmith            {
70967754Smsmith                return_ACPI_STATUS (AE_NO_MEMORY);
71067754Smsmith            }
71167754Smsmith
71267754Smsmith            /* Initialize the new object */
71367754Smsmith
714151937Sjkim            Status = AcpiDsInitObjectFromOp (
715151937Sjkim                        WalkState, Arg, Opcode, &ObjDesc);
71667754Smsmith            if (ACPI_FAILURE (Status))
71767754Smsmith            {
71877424Smsmith                AcpiUtDeleteObjectDesc (ObjDesc);
71967754Smsmith                return_ACPI_STATUS (Status);
72067754Smsmith            }
72199679Siwasaki        }
72267754Smsmith
72367754Smsmith        /* Put the operand object on the object stack */
72467754Smsmith
72567754Smsmith        Status = AcpiDsObjStackPush (ObjDesc, WalkState);
72667754Smsmith        if (ACPI_FAILURE (Status))
72767754Smsmith        {
72867754Smsmith            return_ACPI_STATUS (Status);
72967754Smsmith        }
73067754Smsmith
73191116Smsmith        ACPI_DEBUGGER_EXEC (AcpiDbDisplayArgumentObject (ObjDesc, WalkState));
73267754Smsmith    }
73367754Smsmith
73467754Smsmith    return_ACPI_STATUS (AE_OK);
73567754Smsmith}
73667754Smsmith
73767754Smsmith
73867754Smsmith/*******************************************************************************
73967754Smsmith *
74067754Smsmith * FUNCTION:    AcpiDsCreateOperands
74167754Smsmith *
742151937Sjkim * PARAMETERS:  WalkState           - Current state
743151937Sjkim *              FirstArg            - First argument of a parser argument tree
74467754Smsmith *
74567754Smsmith * RETURN:      Status
74667754Smsmith *
74767754Smsmith * DESCRIPTION: Convert an operator's arguments from a parse tree format to
74867754Smsmith *              namespace objects and place those argument object on the object
74967754Smsmith *              stack in preparation for evaluation by the interpreter.
75067754Smsmith *
75167754Smsmith ******************************************************************************/
75267754Smsmith
75367754SmsmithACPI_STATUS
75467754SmsmithAcpiDsCreateOperands (
75567754Smsmith    ACPI_WALK_STATE         *WalkState,
75667754Smsmith    ACPI_PARSE_OBJECT       *FirstArg)
75767754Smsmith{
75867754Smsmith    ACPI_STATUS             Status = AE_OK;
75967754Smsmith    ACPI_PARSE_OBJECT       *Arg;
760167802Sjkim    ACPI_PARSE_OBJECT       *Arguments[ACPI_OBJ_NUM_OPERANDS];
761193267Sjkim    UINT32                  ArgCount = 0;
762193267Sjkim    UINT32                  Index = WalkState->NumOperands;
763193267Sjkim    UINT32                  i;
76467754Smsmith
76567754Smsmith
766167802Sjkim    ACPI_FUNCTION_TRACE_PTR (DsCreateOperands, FirstArg);
76767754Smsmith
76883174Smsmith
769167802Sjkim    /* Get all arguments in the list */
77067754Smsmith
77169746Smsmith    Arg = FirstArg;
77267754Smsmith    while (Arg)
77367754Smsmith    {
774167802Sjkim        if (Index >= ACPI_OBJ_NUM_OPERANDS)
77567754Smsmith        {
776167802Sjkim            return_ACPI_STATUS (AE_BAD_DATA);
77767754Smsmith        }
77867754Smsmith
779167802Sjkim        Arguments[Index] = Arg;
780167802Sjkim        WalkState->Operands [Index] = NULL;
78167754Smsmith
78267754Smsmith        /* Move on to next argument, if any */
78367754Smsmith
78499679Siwasaki        Arg = Arg->Common.Next;
78569746Smsmith        ArgCount++;
786167802Sjkim        Index++;
78767754Smsmith    }
78867754Smsmith
789281075Sdim    ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
790281075Sdim        "NumOperands %d, ArgCount %d, Index %d\n",
791281075Sdim        WalkState->NumOperands, ArgCount, Index));
792167802Sjkim
793281075Sdim    /* Create the interpreter arguments, in reverse order */
794167802Sjkim
795281075Sdim    Index--;
796167802Sjkim    for (i = 0; i < ArgCount; i++)
797167802Sjkim    {
798167802Sjkim        Arg = Arguments[Index];
799193267Sjkim        WalkState->OperandIndex = (UINT8) Index;
800167802Sjkim
801167802Sjkim        Status = AcpiDsCreateOperand (WalkState, Arg, Index);
802167802Sjkim        if (ACPI_FAILURE (Status))
803167802Sjkim        {
804167802Sjkim            goto Cleanup;
805167802Sjkim        }
806167802Sjkim
807281075Sdim        ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
808281075Sdim            "Created Arg #%u (%p) %u args total\n",
809281075Sdim            Index, Arg, ArgCount));
810167802Sjkim        Index--;
811167802Sjkim    }
812167802Sjkim
81367754Smsmith    return_ACPI_STATUS (Status);
81467754Smsmith
81567754Smsmith
81667754SmsmithCleanup:
81767754Smsmith    /*
81867754Smsmith     * We must undo everything done above; meaning that we must
81967754Smsmith     * pop everything off of the operand stack and delete those
82067754Smsmith     * objects
82167754Smsmith     */
822167802Sjkim    AcpiDsObjStackPopAndDelete (ArgCount, WalkState);
82367754Smsmith
824209746Sjkim    ACPI_EXCEPTION ((AE_INFO, Status, "While creating Arg %u", Index));
82567754Smsmith    return_ACPI_STATUS (Status);
82667754Smsmith}
82767754Smsmith
82867754Smsmith
829167802Sjkim/*****************************************************************************
830167802Sjkim *
831167802Sjkim * FUNCTION:    AcpiDsEvaluateNamePath
832167802Sjkim *
833167802Sjkim * PARAMETERS:  WalkState       - Current state of the parse tree walk,
834167802Sjkim *                                the opcode of current operation should be
835167802Sjkim *                                AML_INT_NAMEPATH_OP
836167802Sjkim *
837167802Sjkim * RETURN:      Status
838167802Sjkim *
839167802Sjkim * DESCRIPTION: Translate the -NamePath- parse tree object to the equivalent
840167802Sjkim *              interpreter object, convert it to value, if needed, duplicate
841167802Sjkim *              it, if needed, and push it onto the current result stack.
842167802Sjkim *
843167802Sjkim ****************************************************************************/
844167802Sjkim
845167802SjkimACPI_STATUS
846167802SjkimAcpiDsEvaluateNamePath (
847167802Sjkim    ACPI_WALK_STATE         *WalkState)
848167802Sjkim{
849167802Sjkim    ACPI_STATUS             Status = AE_OK;
850167802Sjkim    ACPI_PARSE_OBJECT       *Op = WalkState->Op;
851167802Sjkim    ACPI_OPERAND_OBJECT     **Operand = &WalkState->Operands[0];
852167802Sjkim    ACPI_OPERAND_OBJECT     *NewObjDesc;
853167802Sjkim    UINT8                   Type;
854167802Sjkim
855167802Sjkim
856167802Sjkim    ACPI_FUNCTION_TRACE_PTR (DsEvaluateNamePath, WalkState);
857167802Sjkim
858167802Sjkim
859167802Sjkim    if (!Op->Common.Parent)
860167802Sjkim    {
861167802Sjkim        /* This happens after certain exception processing */
862167802Sjkim
863167802Sjkim        goto Exit;
864167802Sjkim    }
865167802Sjkim
866167802Sjkim    if ((Op->Common.Parent->Common.AmlOpcode == AML_PACKAGE_OP) ||
867167802Sjkim        (Op->Common.Parent->Common.AmlOpcode == AML_VAR_PACKAGE_OP) ||
868167802Sjkim        (Op->Common.Parent->Common.AmlOpcode == AML_REF_OF_OP))
869167802Sjkim    {
870167802Sjkim        /* TBD: Should we specify this feature as a bit of OpInfo->Flags of these opcodes? */
871167802Sjkim
872167802Sjkim        goto Exit;
873167802Sjkim    }
874167802Sjkim
875167802Sjkim    Status = AcpiDsCreateOperand (WalkState, Op, 0);
876167802Sjkim    if (ACPI_FAILURE (Status))
877167802Sjkim    {
878167802Sjkim        goto Exit;
879167802Sjkim    }
880167802Sjkim
881167802Sjkim    if (Op->Common.Flags & ACPI_PARSEOP_TARGET)
882167802Sjkim    {
883167802Sjkim        NewObjDesc = *Operand;
884167802Sjkim        goto PushResult;
885167802Sjkim    }
886167802Sjkim
887193267Sjkim    Type = (*Operand)->Common.Type;
888167802Sjkim
889167802Sjkim    Status = AcpiExResolveToValue (Operand, WalkState);
890167802Sjkim    if (ACPI_FAILURE (Status))
891167802Sjkim    {
892167802Sjkim        goto Exit;
893167802Sjkim    }
894167802Sjkim
895167802Sjkim    if (Type == ACPI_TYPE_INTEGER)
896167802Sjkim    {
897167802Sjkim        /* It was incremented by AcpiExResolveToValue */
898167802Sjkim
899167802Sjkim        AcpiUtRemoveReference (*Operand);
900167802Sjkim
901167802Sjkim        Status = AcpiUtCopyIobjectToIobject (*Operand, &NewObjDesc, WalkState);
902167802Sjkim        if (ACPI_FAILURE (Status))
903167802Sjkim        {
904167802Sjkim            goto Exit;
905167802Sjkim        }
906167802Sjkim    }
907167802Sjkim    else
908167802Sjkim    {
909167802Sjkim        /*
910167802Sjkim         * The object either was anew created or is
911167802Sjkim         * a Namespace node - don't decrement it.
912167802Sjkim         */
913167802Sjkim        NewObjDesc = *Operand;
914167802Sjkim    }
915167802Sjkim
916167802Sjkim    /* Cleanup for name-path operand */
917167802Sjkim
918167802Sjkim    Status = AcpiDsObjStackPop (1, WalkState);
919167802Sjkim    if (ACPI_FAILURE (Status))
920167802Sjkim    {
921167802Sjkim        WalkState->ResultObj = NewObjDesc;
922167802Sjkim        goto Exit;
923167802Sjkim    }
924167802Sjkim
925167802SjkimPushResult:
926167802Sjkim
927167802Sjkim    WalkState->ResultObj = NewObjDesc;
928167802Sjkim
929167802Sjkim    Status = AcpiDsResultPush (WalkState->ResultObj, WalkState);
930167802Sjkim    if (ACPI_SUCCESS (Status))
931167802Sjkim    {
932167802Sjkim        /* Force to take it from stack */
933167802Sjkim
934167802Sjkim        Op->Common.Flags |= ACPI_PARSEOP_IN_STACK;
935167802Sjkim    }
936167802Sjkim
937167802SjkimExit:
938167802Sjkim
939167802Sjkim    return_ACPI_STATUS (Status);
940167802Sjkim}
941