167754Smsmith/******************************************************************************
267754Smsmith *
367754Smsmith * Module Name: psparse - Parser top level AML parse routines
467754Smsmith *
567754Smsmith *****************************************************************************/
667754Smsmith
7217365Sjkim/*
8306536Sjkim * Copyright (C) 2000 - 2016, 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
4467754Smsmith/*
4567754Smsmith * Parse the AML and build an operation tree as most interpreters,
46241973Sjkim * like Perl, do. Parsing is done by hand rather than with a YACC
4767754Smsmith * generated parser to tightly constrain stack and dynamic memory
48241973Sjkim * usage. At the same time, parsing is kept flexible and the code
4967754Smsmith * fairly compact by parsing based on a list of AML opcode
5069450Smsmith * templates in AmlOpInfo[]
5167754Smsmith */
5267754Smsmith
53193341Sjkim#include <contrib/dev/acpica/include/acpi.h>
54193341Sjkim#include <contrib/dev/acpica/include/accommon.h>
55193341Sjkim#include <contrib/dev/acpica/include/acparser.h>
56193341Sjkim#include <contrib/dev/acpica/include/acdispat.h>
57193341Sjkim#include <contrib/dev/acpica/include/amlcode.h>
58193341Sjkim#include <contrib/dev/acpica/include/acinterp.h>
5967754Smsmith
6077424Smsmith#define _COMPONENT          ACPI_PARSER
6191116Smsmith        ACPI_MODULE_NAME    ("psparse")
6267754Smsmith
6367754Smsmith
6467754Smsmith/*******************************************************************************
6567754Smsmith *
6683174Smsmith * FUNCTION:    AcpiPsGetOpcodeSize
6767754Smsmith *
6883174Smsmith * PARAMETERS:  Opcode          - An AML opcode
6967754Smsmith *
7083174Smsmith * RETURN:      Size of the opcode, in bytes (1 or 2)
7167754Smsmith *
7283174Smsmith * DESCRIPTION: Get the size of the current opcode.
7367754Smsmith *
7467754Smsmith ******************************************************************************/
7567754Smsmith
7687031SmsmithUINT32
7767754SmsmithAcpiPsGetOpcodeSize (
7867754Smsmith    UINT32                  Opcode)
7967754Smsmith{
8067754Smsmith
8167754Smsmith    /* Extended (2-byte) opcode if > 255 */
8267754Smsmith
8367754Smsmith    if (Opcode > 0x00FF)
8467754Smsmith    {
8567754Smsmith        return (2);
8667754Smsmith    }
8767754Smsmith
8867754Smsmith    /* Otherwise, just a single byte opcode */
8967754Smsmith
9067754Smsmith    return (1);
9167754Smsmith}
9267754Smsmith
9367754Smsmith
9467754Smsmith/*******************************************************************************
9567754Smsmith *
9667754Smsmith * FUNCTION:    AcpiPsPeekOpcode
9767754Smsmith *
9867754Smsmith * PARAMETERS:  ParserState         - A parser state object
9967754Smsmith *
100151937Sjkim * RETURN:      Next AML opcode
10167754Smsmith *
10267754Smsmith * DESCRIPTION: Get next AML opcode (without incrementing AML pointer)
10367754Smsmith *
10467754Smsmith ******************************************************************************/
10567754Smsmith
10667754SmsmithUINT16
10767754SmsmithAcpiPsPeekOpcode (
10867754Smsmith    ACPI_PARSE_STATE        *ParserState)
10967754Smsmith{
11067754Smsmith    UINT8                   *Aml;
11167754Smsmith    UINT16                  Opcode;
11267754Smsmith
11367754Smsmith
11467754Smsmith    Aml = ParserState->Aml;
11591116Smsmith    Opcode = (UINT16) ACPI_GET8 (Aml);
11667754Smsmith
117151937Sjkim    if (Opcode == AML_EXTENDED_OP_PREFIX)
11867754Smsmith    {
119151937Sjkim        /* Extended opcode, get the second opcode byte */
12067754Smsmith
12187031Smsmith        Aml++;
12291116Smsmith        Opcode = (UINT16) ((Opcode << 8) | ACPI_GET8 (Aml));
12367754Smsmith    }
12467754Smsmith
12567754Smsmith    return (Opcode);
12667754Smsmith}
12767754Smsmith
12867754Smsmith
12967754Smsmith/*******************************************************************************
13067754Smsmith *
13167754Smsmith * FUNCTION:    AcpiPsCompleteThisOp
13267754Smsmith *
13367754Smsmith * PARAMETERS:  WalkState       - Current State
13467754Smsmith *              Op              - Op to complete
13567754Smsmith *
136151937Sjkim * RETURN:      Status
13767754Smsmith *
13867754Smsmith * DESCRIPTION: Perform any cleanup at the completion of an Op.
13967754Smsmith *
14067754Smsmith ******************************************************************************/
14167754Smsmith
142151937SjkimACPI_STATUS
14367754SmsmithAcpiPsCompleteThisOp (
14467754Smsmith    ACPI_WALK_STATE         *WalkState,
14567754Smsmith    ACPI_PARSE_OBJECT       *Op)
14667754Smsmith{
14767754Smsmith    ACPI_PARSE_OBJECT       *Prev;
14867754Smsmith    ACPI_PARSE_OBJECT       *Next;
14983174Smsmith    const ACPI_OPCODE_INFO  *ParentInfo;
15067754Smsmith    ACPI_PARSE_OBJECT       *ReplacementOp = NULL;
151193267Sjkim    ACPI_STATUS             Status = AE_OK;
15267754Smsmith
15367754Smsmith
154167802Sjkim    ACPI_FUNCTION_TRACE_PTR (PsCompleteThisOp, Op);
15567754Smsmith
15667754Smsmith
15791116Smsmith    /* Check for null Op, can happen if AML code is corrupt */
15891116Smsmith
15991116Smsmith    if (!Op)
16091116Smsmith    {
161151937Sjkim        return_ACPI_STATUS (AE_OK);  /* OK for now */
16291116Smsmith    }
16391116Smsmith
164306536Sjkim    AcpiExStopTraceOpcode (Op, WalkState);
165306536Sjkim
16667754Smsmith    /* Delete this op and the subtree below it if asked to */
16767754Smsmith
168138287Smarks    if (((WalkState->ParseFlags & ACPI_PARSE_TREE_MASK) != ACPI_PARSE_DELETE_TREE) ||
169138287Smarks         (WalkState->OpInfo->Class == AML_CLASS_ARGUMENT))
17067754Smsmith    {
171151937Sjkim        return_ACPI_STATUS (AE_OK);
172138287Smarks    }
17367754Smsmith
174138287Smarks    /* Make sure that we only delete this subtree */
175138287Smarks
176138287Smarks    if (Op->Common.Parent)
177138287Smarks    {
178151937Sjkim        Prev = Op->Common.Parent->Common.Value.Arg;
179151937Sjkim        if (!Prev)
180151937Sjkim        {
181151937Sjkim            /* Nothing more to do */
182151937Sjkim
183151937Sjkim            goto Cleanup;
184151937Sjkim        }
185151937Sjkim
186138287Smarks        /*
187138287Smarks         * Check if we need to replace the operator and its subtree
188138287Smarks         * with a return value op (placeholder op)
189138287Smarks         */
190151937Sjkim        ParentInfo = AcpiPsGetOpcodeInfo (Op->Common.Parent->Common.AmlOpcode);
191138287Smarks
192138287Smarks        switch (ParentInfo->Class)
19367754Smsmith        {
194138287Smarks        case AML_CLASS_CONTROL:
195250838Sjkim
196138287Smarks            break;
197138287Smarks
198138287Smarks        case AML_CLASS_CREATE:
19967754Smsmith            /*
200241973Sjkim             * These opcodes contain TermArg operands. The current
201138287Smarks             * op must be replaced by a placeholder return op
20267754Smsmith             */
203306536Sjkim            ReplacementOp = AcpiPsAllocOp (
204306536Sjkim                AML_INT_RETURN_VALUE_OP, Op->Common.Aml);
205138287Smarks            if (!ReplacementOp)
20667754Smsmith            {
207193267Sjkim                Status = AE_NO_MEMORY;
208138287Smarks            }
209138287Smarks            break;
21069746Smsmith
211138287Smarks        case AML_CLASS_NAMED_OBJECT:
212138287Smarks            /*
213241973Sjkim             * These opcodes contain TermArg operands. The current
214138287Smarks             * op must be replaced by a placeholder return op
215138287Smarks             */
216138287Smarks            if ((Op->Common.Parent->Common.AmlOpcode == AML_REGION_OP)       ||
217138287Smarks                (Op->Common.Parent->Common.AmlOpcode == AML_DATA_REGION_OP)  ||
218138287Smarks                (Op->Common.Parent->Common.AmlOpcode == AML_BUFFER_OP)       ||
219138287Smarks                (Op->Common.Parent->Common.AmlOpcode == AML_PACKAGE_OP)      ||
220193267Sjkim                (Op->Common.Parent->Common.AmlOpcode == AML_BANK_FIELD_OP)   ||
221138287Smarks                (Op->Common.Parent->Common.AmlOpcode == AML_VAR_PACKAGE_OP))
222138287Smarks            {
223306536Sjkim                ReplacementOp = AcpiPsAllocOp (
224306536Sjkim                    AML_INT_RETURN_VALUE_OP, Op->Common.Aml);
22587031Smsmith                if (!ReplacementOp)
22687031Smsmith                {
227193267Sjkim                    Status = AE_NO_MEMORY;
22887031Smsmith                }
229138287Smarks            }
230151937Sjkim            else if ((Op->Common.Parent->Common.AmlOpcode == AML_NAME_OP) &&
231151937Sjkim                     (WalkState->PassNumber <= ACPI_IMODE_LOAD_PASS2))
232138287Smarks            {
233138287Smarks                if ((Op->Common.AmlOpcode == AML_BUFFER_OP) ||
234138287Smarks                    (Op->Common.AmlOpcode == AML_PACKAGE_OP) ||
235138287Smarks                    (Op->Common.AmlOpcode == AML_VAR_PACKAGE_OP))
23669746Smsmith                {
237306536Sjkim                    ReplacementOp = AcpiPsAllocOp (Op->Common.AmlOpcode,
238306536Sjkim                        Op->Common.Aml);
23969746Smsmith                    if (!ReplacementOp)
24069746Smsmith                    {
241193267Sjkim                        Status = AE_NO_MEMORY;
24269746Smsmith                    }
243193267Sjkim                    else
244193267Sjkim                    {
245193267Sjkim                        ReplacementOp->Named.Data = Op->Named.Data;
246193267Sjkim                        ReplacementOp->Named.Length = Op->Named.Length;
247193267Sjkim                    }
24869746Smsmith                }
249138287Smarks            }
250138287Smarks            break;
25199146Siwasaki
252138287Smarks        default:
253151937Sjkim
254306536Sjkim            ReplacementOp = AcpiPsAllocOp (
255306536Sjkim                AML_INT_RETURN_VALUE_OP, Op->Common.Aml);
256138287Smarks            if (!ReplacementOp)
257138287Smarks            {
258193267Sjkim                Status = AE_NO_MEMORY;
259138287Smarks            }
260138287Smarks        }
26199146Siwasaki
262138287Smarks        /* We must unlink this op from the parent tree */
26399146Siwasaki
264138287Smarks        if (Prev == Op)
265138287Smarks        {
266138287Smarks            /* This op is the first in the list */
26767754Smsmith
268138287Smarks            if (ReplacementOp)
269138287Smarks            {
270306536Sjkim                ReplacementOp->Common.Parent = Op->Common.Parent;
271306536Sjkim                ReplacementOp->Common.Value.Arg = NULL;
272306536Sjkim                ReplacementOp->Common.Node = Op->Common.Node;
273138287Smarks                Op->Common.Parent->Common.Value.Arg = ReplacementOp;
274306536Sjkim                ReplacementOp->Common.Next = Op->Common.Next;
27567754Smsmith            }
276138287Smarks            else
277138287Smarks            {
278138287Smarks                Op->Common.Parent->Common.Value.Arg = Op->Common.Next;
279138287Smarks            }
280138287Smarks        }
28167754Smsmith
282138287Smarks        /* Search the parent list */
28367754Smsmith
284138287Smarks        else while (Prev)
285138287Smarks        {
286138287Smarks            /* Traverse all siblings in the parent's argument list */
287138287Smarks
288138287Smarks            Next = Prev->Common.Next;
289138287Smarks            if (Next == Op)
29067754Smsmith            {
29167754Smsmith                if (ReplacementOp)
29267754Smsmith                {
293306536Sjkim                    ReplacementOp->Common.Parent = Op->Common.Parent;
294138287Smarks                    ReplacementOp->Common.Value.Arg = NULL;
295306536Sjkim                    ReplacementOp->Common.Node = Op->Common.Node;
296306536Sjkim                    Prev->Common.Next = ReplacementOp;
297306536Sjkim                    ReplacementOp->Common.Next = Op->Common.Next;
298138287Smarks                    Next = NULL;
29967754Smsmith                }
30067754Smsmith                else
30167754Smsmith                {
302138287Smarks                    Prev->Common.Next = Op->Common.Next;
303138287Smarks                    Next = NULL;
30467754Smsmith                }
30567754Smsmith            }
306138287Smarks            Prev = Next;
30767754Smsmith        }
308138287Smarks    }
30967754Smsmith
31067754Smsmith
311138287SmarksCleanup:
31267754Smsmith
313151937Sjkim    /* Now we can actually delete the subtree rooted at Op */
31467754Smsmith
315138287Smarks    AcpiPsDeleteParseTree (Op);
316193267Sjkim    return_ACPI_STATUS (Status);
31767754Smsmith}
31867754Smsmith
31967754Smsmith
32067754Smsmith/*******************************************************************************
32167754Smsmith *
32267754Smsmith * FUNCTION:    AcpiPsNextParseState
32367754Smsmith *
324151937Sjkim * PARAMETERS:  WalkState           - Current state
325151937Sjkim *              Op                  - Current parse op
326151937Sjkim *              CallbackStatus      - Status from previous operation
32767754Smsmith *
32899146Siwasaki * RETURN:      Status
32967754Smsmith *
33099146Siwasaki * DESCRIPTION: Update the parser state based upon the return exception from
33199146Siwasaki *              the parser callback.
33267754Smsmith *
33367754Smsmith ******************************************************************************/
33467754Smsmith
33587031SmsmithACPI_STATUS
33667754SmsmithAcpiPsNextParseState (
33767754Smsmith    ACPI_WALK_STATE         *WalkState,
33867754Smsmith    ACPI_PARSE_OBJECT       *Op,
33967754Smsmith    ACPI_STATUS             CallbackStatus)
34067754Smsmith{
34184491Smsmith    ACPI_PARSE_STATE        *ParserState = &WalkState->ParserState;
34267754Smsmith    ACPI_STATUS             Status = AE_CTRL_PENDING;
34367754Smsmith
34467754Smsmith
345167802Sjkim    ACPI_FUNCTION_TRACE_PTR (PsNextParseState, Op);
34667754Smsmith
34767754Smsmith
34867754Smsmith    switch (CallbackStatus)
34967754Smsmith    {
35067754Smsmith    case AE_CTRL_TERMINATE:
35167754Smsmith        /*
35267754Smsmith         * A control method was terminated via a RETURN statement.
35367754Smsmith         * The walk of this method is complete.
35467754Smsmith         */
35567754Smsmith        ParserState->Aml = ParserState->AmlEnd;
35667754Smsmith        Status = AE_CTRL_TERMINATE;
35767754Smsmith        break;
35867754Smsmith
35991116Smsmith    case AE_CTRL_BREAK:
36067754Smsmith
36191116Smsmith        ParserState->Aml = WalkState->AmlLastWhile;
36291116Smsmith        WalkState->ControlState->Common.Value = FALSE;
36391116Smsmith        Status = AE_CTRL_BREAK;
36491116Smsmith        break;
36567754Smsmith
36691116Smsmith    case AE_CTRL_CONTINUE:
36767754Smsmith
36867754Smsmith        ParserState->Aml = WalkState->AmlLastWhile;
36991116Smsmith        Status = AE_CTRL_CONTINUE;
37067754Smsmith        break;
37167754Smsmith
37291116Smsmith    case AE_CTRL_PENDING:
37367754Smsmith
37491116Smsmith        ParserState->Aml = WalkState->AmlLastWhile;
37591116Smsmith        break;
37691116Smsmith
377102550Siwasaki#if 0
378102550Siwasaki    case AE_CTRL_SKIP:
37991116Smsmith
380102550Siwasaki        ParserState->Aml = ParserState->Scope->ParseScope.PkgEnd;
381102550Siwasaki        Status = AE_OK;
382102550Siwasaki        break;
383102550Siwasaki#endif
384102550Siwasaki
38567754Smsmith    case AE_CTRL_TRUE:
38683174Smsmith        /*
38783174Smsmith         * Predicate of an IF was true, and we are at the matching ELSE.
38883174Smsmith         * Just close out this package
38983174Smsmith         */
39091116Smsmith        ParserState->Aml = AcpiPsGetNextPackageEnd (ParserState);
391167802Sjkim        Status = AE_CTRL_PENDING;
39267754Smsmith        break;
39367754Smsmith
39467754Smsmith    case AE_CTRL_FALSE:
39567754Smsmith        /*
39667754Smsmith         * Either an IF/WHILE Predicate was false or we encountered a BREAK
397241973Sjkim         * opcode. In both cases, we do not execute the rest of the
39867754Smsmith         * package;  We simply close out the parent (finishing the walk of
39967754Smsmith         * this branch of the tree) and continue execution at the parent
40067754Smsmith         * level.
40167754Smsmith         */
40267754Smsmith        ParserState->Aml = ParserState->Scope->ParseScope.PkgEnd;
40367754Smsmith
40467754Smsmith        /* In the case of a BREAK, just force a predicate (if any) to FALSE */
40567754Smsmith
40667754Smsmith        WalkState->ControlState->Common.Value = FALSE;
40767754Smsmith        Status = AE_CTRL_END;
40867754Smsmith        break;
40967754Smsmith
41067754Smsmith    case AE_CTRL_TRANSFER:
41167754Smsmith
412151937Sjkim        /* A method call (invocation) -- transfer control */
413151937Sjkim
41467754Smsmith        Status = AE_CTRL_TRANSFER;
41567754Smsmith        WalkState->PrevOp = Op;
41667754Smsmith        WalkState->MethodCallOp = Op;
41799679Siwasaki        WalkState->MethodCallNode = (Op->Common.Value.Arg)->Common.Node;
41867754Smsmith
41967754Smsmith        /* Will return value (if any) be used by the caller? */
42067754Smsmith
42167754Smsmith        WalkState->ReturnUsed = AcpiDsIsResultUsed (Op, WalkState);
42267754Smsmith        break;
42367754Smsmith
42467754Smsmith    default:
425151937Sjkim
42667754Smsmith        Status = CallbackStatus;
42767754Smsmith        if ((CallbackStatus & AE_CODE_MASK) == AE_CODE_CONTROL)
42867754Smsmith        {
42967754Smsmith            Status = AE_OK;
43067754Smsmith        }
43167754Smsmith        break;
43267754Smsmith    }
43367754Smsmith
43467754Smsmith    return_ACPI_STATUS (Status);
43567754Smsmith}
43667754Smsmith
43767754Smsmith
43867754Smsmith/*******************************************************************************
43967754Smsmith *
44067754Smsmith * FUNCTION:    AcpiPsParseAml
44167754Smsmith *
442151937Sjkim * PARAMETERS:  WalkState       - Current state
44367754Smsmith *
44483174Smsmith *
44567754Smsmith * RETURN:      Status
44667754Smsmith *
44767754Smsmith * DESCRIPTION: Parse raw AML and return a tree of ops
44867754Smsmith *
44967754Smsmith ******************************************************************************/
45067754Smsmith
45167754SmsmithACPI_STATUS
45267754SmsmithAcpiPsParseAml (
45384491Smsmith    ACPI_WALK_STATE         *WalkState)
45467754Smsmith{
45567754Smsmith    ACPI_STATUS             Status;
45687031Smsmith    ACPI_THREAD_STATE       *Thread;
45787031Smsmith    ACPI_THREAD_STATE       *PrevWalkList = AcpiGbl_CurrentWalkList;
45884491Smsmith    ACPI_WALK_STATE         *PreviousWalkState;
45967754Smsmith
46067754Smsmith
461167802Sjkim    ACPI_FUNCTION_TRACE (PsParseAml);
46267754Smsmith
463151937Sjkim    ACPI_DEBUG_PRINT ((ACPI_DB_PARSE,
464151937Sjkim        "Entered with WalkState=%p Aml=%p size=%X\n",
465151937Sjkim        WalkState, WalkState->ParserState.Aml,
466151937Sjkim        WalkState->ParserState.AmlSize));
46767754Smsmith
468193267Sjkim    if (!WalkState->ParserState.Aml)
469193267Sjkim    {
470193267Sjkim        return_ACPI_STATUS (AE_NULL_OBJECT);
471193267Sjkim    }
47267754Smsmith
47387031Smsmith    /* Create and initialize a new thread state */
47467754Smsmith
47587031Smsmith    Thread = AcpiUtCreateThreadState ();
47687031Smsmith    if (!Thread)
47787031Smsmith    {
478193267Sjkim        if (WalkState->MethodDesc)
479193267Sjkim        {
480193267Sjkim            /* Executing a control method - additional cleanup */
481193267Sjkim
482193267Sjkim            AcpiDsTerminateControlMethod (WalkState->MethodDesc, WalkState);
483193267Sjkim        }
484193267Sjkim
485167802Sjkim        AcpiDsDeleteWalkState (WalkState);
48687031Smsmith        return_ACPI_STATUS (AE_NO_MEMORY);
48787031Smsmith    }
48867754Smsmith
48987031Smsmith    WalkState->Thread = Thread;
490167802Sjkim
491167802Sjkim    /*
492167802Sjkim     * If executing a method, the starting SyncLevel is this method's
493167802Sjkim     * SyncLevel
494167802Sjkim     */
495167802Sjkim    if (WalkState->MethodDesc)
496167802Sjkim    {
497306536Sjkim        WalkState->Thread->CurrentSyncLevel =
498306536Sjkim            WalkState->MethodDesc->Method.SyncLevel;
499167802Sjkim    }
500167802Sjkim
50187031Smsmith    AcpiDsPushWalkState (WalkState, Thread);
50267754Smsmith
50391116Smsmith    /*
50491116Smsmith     * This global allows the AML debugger to get a handle to the currently
50591116Smsmith     * executing control method.
50667754Smsmith     */
50787031Smsmith    AcpiGbl_CurrentWalkList = Thread;
50867754Smsmith
50967754Smsmith    /*
510241973Sjkim     * Execute the walk loop as long as there is a valid Walk State. This
51167754Smsmith     * handles nested control method invocations without recursion.
51267754Smsmith     */
51382367Smsmith    ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "State=%p\n", WalkState));
51467754Smsmith
51583174Smsmith    Status = AE_OK;
51667754Smsmith    while (WalkState)
51767754Smsmith    {
51867754Smsmith        if (ACPI_SUCCESS (Status))
51967754Smsmith        {
52084491Smsmith            /*
52184491Smsmith             * The ParseLoop executes AML until the method terminates
52284491Smsmith             * or calls another method.
52384491Smsmith             */
52467754Smsmith            Status = AcpiPsParseLoop (WalkState);
52567754Smsmith        }
52667754Smsmith
52783174Smsmith        ACPI_DEBUG_PRINT ((ACPI_DB_PARSE,
528114237Snjl            "Completed one call to walk loop, %s State=%p\n",
529107325Siwasaki            AcpiFormatException (Status), WalkState));
53067754Smsmith
53167754Smsmith        if (Status == AE_CTRL_TRANSFER)
53267754Smsmith        {
53367754Smsmith            /*
53467754Smsmith             * A method call was detected.
53567754Smsmith             * Transfer control to the called control method
53667754Smsmith             */
53787031Smsmith            Status = AcpiDsCallControlMethod (Thread, WalkState, NULL);
538167802Sjkim            if (ACPI_FAILURE (Status))
539167802Sjkim            {
540167802Sjkim                Status = AcpiDsMethodError (Status, WalkState);
541167802Sjkim            }
54267754Smsmith
54367754Smsmith            /*
544306536Sjkim             * If the transfer to the new method method call worked
545306536Sjkim             *, a new walk state was created -- get it
54667754Smsmith             */
54787031Smsmith            WalkState = AcpiDsGetCurrentWalkState (Thread);
54867754Smsmith            continue;
54967754Smsmith        }
55067754Smsmith        else if (Status == AE_CTRL_TERMINATE)
55167754Smsmith        {
55267754Smsmith            Status = AE_OK;
55367754Smsmith        }
554138287Smarks        else if ((Status != AE_OK) && (WalkState->MethodDesc))
555107325Siwasaki        {
556167802Sjkim            /* Either the method parse or actual execution failed */
557167802Sjkim
558167802Sjkim            ACPI_ERROR_METHOD ("Method parse/execution failed",
559114237Snjl                WalkState->MethodNode, NULL, Status);
560127175Snjl
561127175Snjl            /* Check for possible multi-thread reentrancy problem */
562127175Snjl
563127175Snjl            if ((Status == AE_ALREADY_EXISTS) &&
564306536Sjkim                (!(WalkState->MethodDesc->Method.InfoFlags &
565306536Sjkim                    ACPI_METHOD_SERIALIZED)))
566127175Snjl            {
567127175Snjl                /*
568217365Sjkim                 * Method is not serialized and tried to create an object
569217365Sjkim                 * twice. The probable cause is that the method cannot
570217365Sjkim                 * handle reentrancy. Mark as "pending serialized" now, and
571217365Sjkim                 * then mark "serialized" when the last thread exits.
572127175Snjl                 */
573217365Sjkim                WalkState->MethodDesc->Method.InfoFlags |=
574217365Sjkim                    ACPI_METHOD_SERIALIZED_PENDING;
575127175Snjl            }
576107325Siwasaki        }
57767754Smsmith
57867754Smsmith        /* We are done with this walk, move on to the parent if any */
57967754Smsmith
58087031Smsmith        WalkState = AcpiDsPopWalkState (Thread);
58167754Smsmith
58267754Smsmith        /* Reset the current scope to the beginning of scope stack */
58367754Smsmith
58467754Smsmith        AcpiDsScopeStackClear (WalkState);
58567754Smsmith
58667754Smsmith        /*
587167802Sjkim         * If we just returned from the execution of a control method or if we
588167802Sjkim         * encountered an error during the method parse phase, there's lots of
589167802Sjkim         * cleanup to do
59067754Smsmith         */
591306536Sjkim        if (((WalkState->ParseFlags & ACPI_PARSE_MODE_MASK) ==
592306536Sjkim            ACPI_PARSE_EXECUTE) ||
593167802Sjkim            (ACPI_FAILURE (Status)))
59467754Smsmith        {
595167802Sjkim            AcpiDsTerminateControlMethod (WalkState->MethodDesc, WalkState);
59667754Smsmith        }
59767754Smsmith
59883174Smsmith        /* Delete this walk state and all linked control states */
59967754Smsmith
60084491Smsmith        AcpiPsCleanupScope (&WalkState->ParserState);
60184491Smsmith        PreviousWalkState = WalkState;
60284491Smsmith
603151937Sjkim        ACPI_DEBUG_PRINT ((ACPI_DB_PARSE,
604151937Sjkim            "ReturnValue=%p, ImplicitValue=%p State=%p\n",
605151937Sjkim            WalkState->ReturnDesc, WalkState->ImplicitReturnObj, WalkState));
60684491Smsmith
60783174Smsmith        /* Check if we have restarted a preempted walk */
60867754Smsmith
60987031Smsmith        WalkState = AcpiDsGetCurrentWalkState (Thread);
61084491Smsmith        if (WalkState)
61167754Smsmith        {
61284491Smsmith            if (ACPI_SUCCESS (Status))
61384491Smsmith            {
61484491Smsmith                /*
61591116Smsmith                 * There is another walk state, restart it.
61691116Smsmith                 * If the method return value is not used by the parent,
61784491Smsmith                 * The object is deleted
61884491Smsmith                 */
619151937Sjkim                if (!PreviousWalkState->ReturnDesc)
620151937Sjkim                {
621193267Sjkim                    /*
622193267Sjkim                     * In slack mode execution, if there is no return value
623193267Sjkim                     * we should implicitly return zero (0) as a default value.
624193267Sjkim                     */
625193267Sjkim                    if (AcpiGbl_EnableInterpreterSlack &&
626193267Sjkim                        !PreviousWalkState->ImplicitReturnObj)
627193267Sjkim                    {
628193267Sjkim                        PreviousWalkState->ImplicitReturnObj =
629199337Sjkim                            AcpiUtCreateIntegerObject ((UINT64) 0);
630193267Sjkim                        if (!PreviousWalkState->ImplicitReturnObj)
631193267Sjkim                        {
632193267Sjkim                            return_ACPI_STATUS (AE_NO_MEMORY);
633193267Sjkim                        }
634193267Sjkim                    }
635193267Sjkim
636193267Sjkim                    /* Restart the calling control method */
637193267Sjkim
638151937Sjkim                    Status = AcpiDsRestartControlMethod (WalkState,
639306536Sjkim                        PreviousWalkState->ImplicitReturnObj);
640151937Sjkim                }
641151937Sjkim                else
642151937Sjkim                {
643151937Sjkim                    /*
644151937Sjkim                     * We have a valid return value, delete any implicit
645151937Sjkim                     * return value.
646151937Sjkim                     */
647151937Sjkim                    AcpiDsClearImplicitReturn (PreviousWalkState);
648151937Sjkim
649151937Sjkim                    Status = AcpiDsRestartControlMethod (WalkState,
650306536Sjkim                        PreviousWalkState->ReturnDesc);
651151937Sjkim                }
65299679Siwasaki                if (ACPI_SUCCESS (Status))
65399679Siwasaki                {
65499679Siwasaki                    WalkState->WalkType |= ACPI_WALK_METHOD_RESTART;
65599679Siwasaki                }
65684491Smsmith            }
65791116Smsmith            else
65891116Smsmith            {
659193267Sjkim                /* On error, delete any return object or implicit return */
66091116Smsmith
66191116Smsmith                AcpiUtRemoveReference (PreviousWalkState->ReturnDesc);
662193267Sjkim                AcpiDsClearImplicitReturn (PreviousWalkState);
66391116Smsmith            }
66467754Smsmith        }
66567754Smsmith
66667754Smsmith        /*
66767754Smsmith         * Just completed a 1st-level method, save the final internal return
66867754Smsmith         * value (if any)
66967754Smsmith         */
67084491Smsmith        else if (PreviousWalkState->CallerReturnDesc)
67167754Smsmith        {
672151937Sjkim            if (PreviousWalkState->ImplicitReturnObj)
673151937Sjkim            {
674151937Sjkim                *(PreviousWalkState->CallerReturnDesc) =
675151937Sjkim                    PreviousWalkState->ImplicitReturnObj;
676151937Sjkim            }
677151937Sjkim            else
678151937Sjkim            {
679151937Sjkim                 /* NULL if no return value */
680151937Sjkim
681151937Sjkim                *(PreviousWalkState->CallerReturnDesc) =
682151937Sjkim                    PreviousWalkState->ReturnDesc;
683151937Sjkim            }
68467754Smsmith        }
685151937Sjkim        else
68667754Smsmith        {
687151937Sjkim            if (PreviousWalkState->ReturnDesc)
688151937Sjkim            {
689151937Sjkim                /* Caller doesn't want it, must delete it */
69067754Smsmith
691151937Sjkim                AcpiUtRemoveReference (PreviousWalkState->ReturnDesc);
692151937Sjkim            }
693151937Sjkim            if (PreviousWalkState->ImplicitReturnObj)
694151937Sjkim            {
695151937Sjkim                /* Caller doesn't want it, must delete it */
696151937Sjkim
697151937Sjkim                AcpiUtRemoveReference (PreviousWalkState->ImplicitReturnObj);
698151937Sjkim            }
69967754Smsmith        }
70084491Smsmith
70184491Smsmith        AcpiDsDeleteWalkState (PreviousWalkState);
70267754Smsmith    }
70367754Smsmith
70467754Smsmith    /* Normal exit */
70567754Smsmith
70687031Smsmith    AcpiExReleaseAllMutexes (Thread);
70799679Siwasaki    AcpiUtDeleteGenericState (ACPI_CAST_PTR (ACPI_GENERIC_STATE, Thread));
70867754Smsmith    AcpiGbl_CurrentWalkList = PrevWalkList;
70967754Smsmith    return_ACPI_STATUS (Status);
71067754Smsmith}
711