117680Spst/******************************************************************************
239300Sfenner *
317680Spst * Module Name: psparse - Parser top level AML parse routines
417680Spst *
517680Spst *****************************************************************************/
617680Spst
717680Spst/*
817680Spst * Copyright (C) 2000 - 2016, Intel Corp.
917680Spst * All rights reserved.
1017680Spst *
1117680Spst * Redistribution and use in source and binary forms, with or without
1217680Spst * modification, are permitted provided that the following conditions
1317680Spst * are met:
1417680Spst * 1. Redistributions of source code must retain the above copyright
1517680Spst *    notice, this list of conditions, and the following disclaimer,
1617680Spst *    without modification.
1717680Spst * 2. Redistributions in binary form must reproduce at minimum a disclaimer
1817680Spst *    substantially similar to the "NO WARRANTY" disclaimer below
1917680Spst *    ("Disclaimer") and any redistribution must be conditioned upon
2053146Sbrian *    including a substantially similar Disclaimer requirement for further
2175118Sfenner *    binary redistribution.
2275118Sfenner * 3. Neither the names of the above-listed copyright holders nor the names
2375118Sfenner *    of any contributors may be used to endorse or promote products derived
2453146Sbrian *    from this software without specific prior written permission.
2517680Spst *
2617680Spst * Alternatively, this software may be distributed under the terms of the
2775118Sfenner * GNU General Public License ("GPL") version 2 as published by the Free
2875118Sfenner * Software Foundation.
2975118Sfenner *
3075118Sfenner * NO WARRANTY
3175118Sfenner * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
3275118Sfenner * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
3375118Sfenner * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
3417680Spst * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
35127675Sbms * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36190207Srpaulo * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3717680Spst * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3817680Spst * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
3956896Sfenner * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
4056896Sfenner * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
4156896Sfenner * POSSIBILITY OF SUCH DAMAGES.
4256896Sfenner */
43127675Sbms
4417680Spst/*
4575118Sfenner * Parse the AML and build an operation tree as most interpreters,
4675118Sfenner * like Perl, do. Parsing is done by hand rather than with a YACC
4775118Sfenner * generated parser to tightly constrain stack and dynamic memory
4817680Spst * usage. At the same time, parsing is kept flexible and the code
4917680Spst * fairly compact by parsing based on a list of AML opcode
5017680Spst * templates in AmlOpInfo[]
5117680Spst */
52146778Ssam
5317680Spst#include <contrib/dev/acpica/include/acpi.h>
5417680Spst#include <contrib/dev/acpica/include/accommon.h>
5556896Sfenner#include <contrib/dev/acpica/include/acparser.h>
5617680Spst#include <contrib/dev/acpica/include/acdispat.h>
5739300Sfenner#include <contrib/dev/acpica/include/amlcode.h>
5875118Sfenner#include <contrib/dev/acpica/include/acinterp.h>
5975118Sfenner
60146778Ssam#define _COMPONENT          ACPI_PARSER
6117680Spst        ACPI_MODULE_NAME    ("psparse")
6275118Sfenner
6375118Sfenner
6475118Sfenner/*******************************************************************************
6575118Sfenner *
6675118Sfenner * FUNCTION:    AcpiPsGetOpcodeSize
6717680Spst *
68127675Sbms * PARAMETERS:  Opcode          - An AML opcode
6917692Spst *
70127675Sbms * RETURN:      Size of the opcode, in bytes (1 or 2)
71127675Sbms *
72127675Sbms * DESCRIPTION: Get the size of the current opcode.
73127675Sbms *
74127675Sbms ******************************************************************************/
75127675Sbms
76127675SbmsUINT32
77146778SsamAcpiPsGetOpcodeSize (
78146778Ssam    UINT32                  Opcode)
79127675Sbms{
80127675Sbms
81127675Sbms    /* Extended (2-byte) opcode if > 255 */
82127675Sbms
83127675Sbms    if (Opcode > 0x00FF)
84146778Ssam    {
85146778Ssam        return (2);
86146778Ssam    }
87127675Sbms
88127675Sbms    /* Otherwise, just a single byte opcode */
89127675Sbms
90127675Sbms    return (1);
91127675Sbms}
92127675Sbms
93127675Sbms
94127675Sbms/*******************************************************************************
95127675Sbms *
96127675Sbms * FUNCTION:    AcpiPsPeekOpcode
97127675Sbms *
98127675Sbms * PARAMETERS:  ParserState         - A parser state object
99146778Ssam *
100127675Sbms * RETURN:      Next AML opcode
101127675Sbms *
102127675Sbms * DESCRIPTION: Get next AML opcode (without incrementing AML pointer)
103127675Sbms *
104127675Sbms ******************************************************************************/
105127675Sbms
106146778SsamUINT16
107146778SsamAcpiPsPeekOpcode (
108146778Ssam    ACPI_PARSE_STATE        *ParserState)
109127675Sbms{
110127675Sbms    UINT8                   *Aml;
111146778Ssam    UINT16                  Opcode;
112127675Sbms
113127675Sbms
114127675Sbms    Aml = ParserState->Aml;
115127675Sbms    Opcode = (UINT16) ACPI_GET8 (Aml);
116127675Sbms
11775118Sfenner    if (Opcode == AML_EXTENDED_OP_PREFIX)
11875118Sfenner    {
11975118Sfenner        /* Extended opcode, get the second opcode byte */
12075118Sfenner
12175118Sfenner        Aml++;
12275118Sfenner        Opcode = (UINT16) ((Opcode << 8) | ACPI_GET8 (Aml));
12375118Sfenner    }
12475118Sfenner
12575118Sfenner    return (Opcode);
12675118Sfenner}
12775118Sfenner
12875118Sfenner
129127675Sbms/*******************************************************************************
130127675Sbms *
131127675Sbms * FUNCTION:    AcpiPsCompleteThisOp
13275118Sfenner *
13338638Sthepish * PARAMETERS:  WalkState       - Current State
134127675Sbms *              Op              - Op to complete
135127675Sbms *
136127675Sbms * RETURN:      Status
137127675Sbms *
138127675Sbms * DESCRIPTION: Perform any cleanup at the completion of an Op.
139127675Sbms *
140127675Sbms ******************************************************************************/
141127675Sbms
142127675SbmsACPI_STATUS
143127675SbmsAcpiPsCompleteThisOp (
144127675Sbms    ACPI_WALK_STATE         *WalkState,
145127675Sbms    ACPI_PARSE_OBJECT       *Op)
146127675Sbms{
147127675Sbms    ACPI_PARSE_OBJECT       *Prev;
148127675Sbms    ACPI_PARSE_OBJECT       *Next;
149127675Sbms    const ACPI_OPCODE_INFO  *ParentInfo;
150127675Sbms    ACPI_PARSE_OBJECT       *ReplacementOp = NULL;
151127675Sbms    ACPI_STATUS             Status = AE_OK;
15238638Sthepish
15338638Sthepish
15475118Sfenner    ACPI_FUNCTION_TRACE_PTR (PsCompleteThisOp, Op);
15575118Sfenner
15638638Sthepish
15738638Sthepish    /* Check for null Op, can happen if AML code is corrupt */
15838638Sthepish
15938638Sthepish    if (!Op)
16038638Sthepish    {
16138638Sthepish        return_ACPI_STATUS (AE_OK);  /* OK for now */
16275118Sfenner    }
16338638Sthepish
16438638Sthepish    AcpiExStopTraceOpcode (Op, WalkState);
16575118Sfenner
16675118Sfenner    /* Delete this op and the subtree below it if asked to */
16775118Sfenner
16875118Sfenner    if (((WalkState->ParseFlags & ACPI_PARSE_TREE_MASK) != ACPI_PARSE_DELETE_TREE) ||
16975118Sfenner         (WalkState->OpInfo->Class == AML_CLASS_ARGUMENT))
17075118Sfenner    {
17175118Sfenner        return_ACPI_STATUS (AE_OK);
17275118Sfenner    }
17375118Sfenner
17475118Sfenner    /* Make sure that we only delete this subtree */
17575118Sfenner
17675118Sfenner    if (Op->Common.Parent)
17775118Sfenner    {
17875118Sfenner        Prev = Op->Common.Parent->Common.Value.Arg;
17975118Sfenner        if (!Prev)
18075118Sfenner        {
18175118Sfenner            /* Nothing more to do */
18275118Sfenner
18375118Sfenner            goto Cleanup;
18475118Sfenner        }
18575118Sfenner
18675118Sfenner        /*
18738638Sthepish         * Check if we need to replace the operator and its subtree
18875118Sfenner         * with a return value op (placeholder op)
18975118Sfenner         */
19038638Sthepish        ParentInfo = AcpiPsGetOpcodeInfo (Op->Common.Parent->Common.AmlOpcode);
19175118Sfenner
19275118Sfenner        switch (ParentInfo->Class)
19375118Sfenner        {
19475118Sfenner        case AML_CLASS_CONTROL:
19575118Sfenner
19675118Sfenner            break;
19775118Sfenner
19875118Sfenner        case AML_CLASS_CREATE:
19975118Sfenner            /*
20075118Sfenner             * These opcodes contain TermArg operands. The current
20175118Sfenner             * op must be replaced by a placeholder return op
20275118Sfenner             */
20375118Sfenner            ReplacementOp = AcpiPsAllocOp (
20475118Sfenner                AML_INT_RETURN_VALUE_OP, Op->Common.Aml);
20575118Sfenner            if (!ReplacementOp)
20675118Sfenner            {
20775118Sfenner                Status = AE_NO_MEMORY;
20875118Sfenner            }
20975118Sfenner            break;
210146778Ssam
21175118Sfenner        case AML_CLASS_NAMED_OBJECT:
21275118Sfenner            /*
21375118Sfenner             * These opcodes contain TermArg operands. The current
21475118Sfenner             * op must be replaced by a placeholder return op
21575118Sfenner             */
21675118Sfenner            if ((Op->Common.Parent->Common.AmlOpcode == AML_REGION_OP)       ||
21775118Sfenner                (Op->Common.Parent->Common.AmlOpcode == AML_DATA_REGION_OP)  ||
21875118Sfenner                (Op->Common.Parent->Common.AmlOpcode == AML_BUFFER_OP)       ||
21975118Sfenner                (Op->Common.Parent->Common.AmlOpcode == AML_PACKAGE_OP)      ||
22075118Sfenner                (Op->Common.Parent->Common.AmlOpcode == AML_BANK_FIELD_OP)   ||
22175118Sfenner                (Op->Common.Parent->Common.AmlOpcode == AML_VAR_PACKAGE_OP))
22275118Sfenner            {
22338638Sthepish                ReplacementOp = AcpiPsAllocOp (
22438638Sthepish                    AML_INT_RETURN_VALUE_OP, Op->Common.Aml);
22575118Sfenner                if (!ReplacementOp)
22675118Sfenner                {
22775118Sfenner                    Status = AE_NO_MEMORY;
22875118Sfenner                }
22975118Sfenner            }
23075118Sfenner            else if ((Op->Common.Parent->Common.AmlOpcode == AML_NAME_OP) &&
23175118Sfenner                     (WalkState->PassNumber <= ACPI_IMODE_LOAD_PASS2))
23275118Sfenner            {
23375118Sfenner                if ((Op->Common.AmlOpcode == AML_BUFFER_OP) ||
23475118Sfenner                    (Op->Common.AmlOpcode == AML_PACKAGE_OP) ||
23575118Sfenner                    (Op->Common.AmlOpcode == AML_VAR_PACKAGE_OP))
23675118Sfenner                {
23775118Sfenner                    ReplacementOp = AcpiPsAllocOp (Op->Common.AmlOpcode,
23875118Sfenner                        Op->Common.Aml);
23975118Sfenner                    if (!ReplacementOp)
24075118Sfenner                    {
24175118Sfenner                        Status = AE_NO_MEMORY;
24275118Sfenner                    }
24375118Sfenner                    else
24475118Sfenner                    {
24575118Sfenner                        ReplacementOp->Named.Data = Op->Named.Data;
24675118Sfenner                        ReplacementOp->Named.Length = Op->Named.Length;
24775118Sfenner                    }
248147904Ssam                }
249147904Ssam            }
250147904Ssam            break;
251147904Ssam
252147904Ssam        default:
253147904Ssam
254147904Ssam            ReplacementOp = AcpiPsAllocOp (
255147904Ssam                AML_INT_RETURN_VALUE_OP, Op->Common.Aml);
256147904Ssam            if (!ReplacementOp)
257147904Ssam            {
258147904Ssam                Status = AE_NO_MEMORY;
259147904Ssam            }
260147904Ssam        }
261147904Ssam
262147904Ssam        /* We must unlink this op from the parent tree */
263147904Ssam
264147904Ssam        if (Prev == Op)
26575118Sfenner        {
26675118Sfenner            /* This op is the first in the list */
26775118Sfenner
26875118Sfenner            if (ReplacementOp)
26975118Sfenner            {
27075118Sfenner                ReplacementOp->Common.Parent = Op->Common.Parent;
271147904Ssam                ReplacementOp->Common.Value.Arg = NULL;
272147904Ssam                ReplacementOp->Common.Node = Op->Common.Node;
273147904Ssam                Op->Common.Parent->Common.Value.Arg = ReplacementOp;
274147904Ssam                ReplacementOp->Common.Next = Op->Common.Next;
275147904Ssam            }
276147904Ssam            else
27775118Sfenner            {
27875118Sfenner                Op->Common.Parent->Common.Value.Arg = Op->Common.Next;
27975118Sfenner            }
28075118Sfenner        }
28175118Sfenner
28275118Sfenner        /* Search the parent list */
28375118Sfenner
28475118Sfenner        else while (Prev)
28575118Sfenner        {
28675118Sfenner            /* Traverse all siblings in the parent's argument list */
28775118Sfenner
28875118Sfenner            Next = Prev->Common.Next;
289146778Ssam            if (Next == Op)
290146778Ssam            {
291146778Ssam                if (ReplacementOp)
292146778Ssam                {
293146778Ssam                    ReplacementOp->Common.Parent = Op->Common.Parent;
294146778Ssam                    ReplacementOp->Common.Value.Arg = NULL;
295146778Ssam                    ReplacementOp->Common.Node = Op->Common.Node;
296146778Ssam                    Prev->Common.Next = ReplacementOp;
297146778Ssam                    ReplacementOp->Common.Next = Op->Common.Next;
298146778Ssam                    Next = NULL;
299146778Ssam                }
300146778Ssam                else
301172686Smlaier                {
302172686Smlaier                    Prev->Common.Next = Op->Common.Next;
303146778Ssam                    Next = NULL;
304172686Smlaier                }
305172686Smlaier            }
306172686Smlaier            Prev = Next;
307172686Smlaier        }
308172686Smlaier    }
309172686Smlaier
310172686Smlaier
311172686SmlaierCleanup:
312172686Smlaier
313172686Smlaier    /* Now we can actually delete the subtree rooted at Op */
314172686Smlaier
315172686Smlaier    AcpiPsDeleteParseTree (Op);
316146778Ssam    return_ACPI_STATUS (Status);
317146778Ssam}
318146778Ssam
319146778Ssam
320146778Ssam/*******************************************************************************
321146778Ssam *
322146778Ssam * FUNCTION:    AcpiPsNextParseState
323146778Ssam *
32475118Sfenner * PARAMETERS:  WalkState           - Current state
32575118Sfenner *              Op                  - Current parse op
32675118Sfenner *              CallbackStatus      - Status from previous operation
32775118Sfenner *
32875118Sfenner * RETURN:      Status
329127675Sbms *
33075118Sfenner * DESCRIPTION: Update the parser state based upon the return exception from
33175118Sfenner *              the parser callback.
33275118Sfenner *
33375118Sfenner ******************************************************************************/
33475118Sfenner
33575118SfennerACPI_STATUS
33675118SfennerAcpiPsNextParseState (
33775118Sfenner    ACPI_WALK_STATE         *WalkState,
338146778Ssam    ACPI_PARSE_OBJECT       *Op,
339146778Ssam    ACPI_STATUS             CallbackStatus)
340146778Ssam{
341146778Ssam    ACPI_PARSE_STATE        *ParserState = &WalkState->ParserState;
342146778Ssam    ACPI_STATUS             Status = AE_CTRL_PENDING;
343146778Ssam
344146778Ssam
34575118Sfenner    ACPI_FUNCTION_TRACE_PTR (PsNextParseState, Op);
34675118Sfenner
34775118Sfenner
34875118Sfenner    switch (CallbackStatus)
34975118Sfenner    {
35075118Sfenner    case AE_CTRL_TERMINATE:
35175118Sfenner        /*
35275118Sfenner         * A control method was terminated via a RETURN statement.
35375118Sfenner         * The walk of this method is complete.
35475118Sfenner         */
35575118Sfenner        ParserState->Aml = ParserState->AmlEnd;
35675118Sfenner        Status = AE_CTRL_TERMINATE;
35775118Sfenner        break;
35875118Sfenner
35975118Sfenner    case AE_CTRL_BREAK:
36075118Sfenner
36175118Sfenner        ParserState->Aml = WalkState->AmlLastWhile;
36275118Sfenner        WalkState->ControlState->Common.Value = FALSE;
363147904Ssam        Status = AE_CTRL_BREAK;
364147904Ssam        break;
365147904Ssam
366147904Ssam    case AE_CTRL_CONTINUE:
367147904Ssam
368147904Ssam        ParserState->Aml = WalkState->AmlLastWhile;
369147904Ssam        Status = AE_CTRL_CONTINUE;
370147904Ssam        break;
371147904Ssam
372147904Ssam    case AE_CTRL_PENDING:
37338638Sthepish
37438638Sthepish        ParserState->Aml = WalkState->AmlLastWhile;
37538638Sthepish        break;
37638638Sthepish
37738638Sthepish#if 0
37838638Sthepish    case AE_CTRL_SKIP:
37938638Sthepish
380146778Ssam        ParserState->Aml = ParserState->Scope->ParseScope.PkgEnd;
381146778Ssam        Status = AE_OK;
382146778Ssam        break;
383146778Ssam#endif
384146778Ssam
385146778Ssam    case AE_CTRL_TRUE:
38638638Sthepish        /*
38738638Sthepish         * Predicate of an IF was true, and we are at the matching ELSE.
38838638Sthepish         * Just close out this package
38938638Sthepish         */
39038638Sthepish        ParserState->Aml = AcpiPsGetNextPackageEnd (ParserState);
39138638Sthepish        Status = AE_CTRL_PENDING;
39238638Sthepish        break;
39338638Sthepish
394146778Ssam    case AE_CTRL_FALSE:
395146778Ssam        /*
396146778Ssam         * Either an IF/WHILE Predicate was false or we encountered a BREAK
397146778Ssam         * opcode. In both cases, we do not execute the rest of the
398146778Ssam         * package;  We simply close out the parent (finishing the walk of
39938638Sthepish         * this branch of the tree) and continue execution at the parent
40038638Sthepish         * level.
40175118Sfenner         */
40275118Sfenner        ParserState->Aml = ParserState->Scope->ParseScope.PkgEnd;
40375118Sfenner
40475118Sfenner        /* In the case of a BREAK, just force a predicate (if any) to FALSE */
40575118Sfenner
40675118Sfenner        WalkState->ControlState->Common.Value = FALSE;
40775118Sfenner        Status = AE_CTRL_END;
40875118Sfenner        break;
40975118Sfenner
41038638Sthepish    case AE_CTRL_TRANSFER:
41175118Sfenner
41275118Sfenner        /* A method call (invocation) -- transfer control */
41375118Sfenner
41475118Sfenner        Status = AE_CTRL_TRANSFER;
415146778Ssam        WalkState->PrevOp = Op;
41675118Sfenner        WalkState->MethodCallOp = Op;
41775118Sfenner        WalkState->MethodCallNode = (Op->Common.Value.Arg)->Common.Node;
418146778Ssam
41975118Sfenner        /* Will return value (if any) be used by the caller? */
42075118Sfenner
42175118Sfenner        WalkState->ReturnUsed = AcpiDsIsResultUsed (Op, WalkState);
422146778Ssam        break;
42338638Sthepish
42475118Sfenner    default:
42556896Sfenner
426127675Sbms        Status = CallbackStatus;
42717680Spst        if ((CallbackStatus & AE_CODE_MASK) == AE_CODE_CONTROL)
428127675Sbms        {
42975118Sfenner            Status = AE_OK;
43075118Sfenner        }
43138638Sthepish        break;
432127675Sbms    }
43317680Spst
434127675Sbms    return_ACPI_STATUS (Status);
43532149Spst}
436146778Ssam
437127675Sbms
43832149Spst/*******************************************************************************
439127675Sbms *
440127675Sbms * FUNCTION:    AcpiPsParseAml
441127675Sbms *
44275118Sfenner * PARAMETERS:  WalkState       - Current state
443127675Sbms *
444127675Sbms *
445147904Ssam * RETURN:      Status
446127675Sbms *
447147904Ssam * DESCRIPTION: Parse raw AML and return a tree of ops
448147904Ssam *
449147904Ssam ******************************************************************************/
45075118Sfenner
451147904SsamACPI_STATUS
452147904SsamAcpiPsParseAml (
453147904Ssam    ACPI_WALK_STATE         *WalkState)
454147904Ssam{
455147904Ssam    ACPI_STATUS             Status;
456147904Ssam    ACPI_THREAD_STATE       *Thread;
457127675Sbms    ACPI_THREAD_STATE       *PrevWalkList = AcpiGbl_CurrentWalkList;
458127675Sbms    ACPI_WALK_STATE         *PreviousWalkState;
459127675Sbms
460127675Sbms
461147904Ssam    ACPI_FUNCTION_TRACE (PsParseAml);
46275118Sfenner
463147904Ssam    ACPI_DEBUG_PRINT ((ACPI_DB_PARSE,
464147904Ssam        "Entered with WalkState=%p Aml=%p size=%X\n",
465147904Ssam        WalkState, WalkState->ParserState.Aml,
466147904Ssam        WalkState->ParserState.AmlSize));
46775118Sfenner
46875118Sfenner    if (!WalkState->ParserState.Aml)
46975118Sfenner    {
47075118Sfenner        return_ACPI_STATUS (AE_NULL_OBJECT);
471127675Sbms    }
472147904Ssam
473127675Sbms    /* Create and initialize a new thread state */
474127675Sbms
475146778Ssam    Thread = AcpiUtCreateThreadState ();
476146778Ssam    if (!Thread)
477146778Ssam    {
47875118Sfenner        if (WalkState->MethodDesc)
47975118Sfenner        {
48075118Sfenner            /* Executing a control method - additional cleanup */
48175118Sfenner
48275118Sfenner            AcpiDsTerminateControlMethod (WalkState->MethodDesc, WalkState);
48375118Sfenner        }
48475118Sfenner
48556896Sfenner        AcpiDsDeleteWalkState (WalkState);
48675118Sfenner        return_ACPI_STATUS (AE_NO_MEMORY);
48775118Sfenner    }
48875118Sfenner
48956896Sfenner    WalkState->Thread = Thread;
49075118Sfenner
49175118Sfenner    /*
49275118Sfenner     * If executing a method, the starting SyncLevel is this method's
493146778Ssam     * SyncLevel
494146778Ssam     */
495146778Ssam    if (WalkState->MethodDesc)
49675118Sfenner    {
49775118Sfenner        WalkState->Thread->CurrentSyncLevel =
49875118Sfenner            WalkState->MethodDesc->Method.SyncLevel;
49975118Sfenner    }
50075118Sfenner
50175118Sfenner    AcpiDsPushWalkState (WalkState, Thread);
50275118Sfenner
50375118Sfenner    /*
504146778Ssam     * This global allows the AML debugger to get a handle to the currently
505146778Ssam     * executing control method.
50675118Sfenner     */
50775118Sfenner    AcpiGbl_CurrentWalkList = Thread;
50875118Sfenner
50975118Sfenner    /*
510140744Sbms     * Execute the walk loop as long as there is a valid Walk State. This
511146778Ssam     * handles nested control method invocations without recursion.
512146778Ssam     */
513146778Ssam    ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "State=%p\n", WalkState));
514127675Sbms
51575118Sfenner    Status = AE_OK;
51656896Sfenner    while (WalkState)
517127675Sbms    {
51856896Sfenner        if (ACPI_SUCCESS (Status))
51956896Sfenner        {
52032149Spst            /*
52175118Sfenner             * The ParseLoop executes AML until the method terminates
52275118Sfenner             * or calls another method.
52375118Sfenner             */
52456896Sfenner            Status = AcpiPsParseLoop (WalkState);
52575118Sfenner        }
52675118Sfenner
52775118Sfenner        ACPI_DEBUG_PRINT ((ACPI_DB_PARSE,
52875118Sfenner            "Completed one call to walk loop, %s State=%p\n",
52975118Sfenner            AcpiFormatException (Status), WalkState));
53075118Sfenner
531127675Sbms        if (Status == AE_CTRL_TRANSFER)
532147904Ssam        {
533127675Sbms            /*
534127675Sbms             * A method call was detected.
535147904Ssam             * Transfer control to the called control method
536147904Ssam             */
537147904Ssam            Status = AcpiDsCallControlMethod (Thread, WalkState, NULL);
538147904Ssam            if (ACPI_FAILURE (Status))
539147904Ssam            {
54075118Sfenner                Status = AcpiDsMethodError (Status, WalkState);
54175118Sfenner            }
54275118Sfenner
54375118Sfenner            /*
544147904Ssam             * If the transfer to the new method method call worked
545147904Ssam             *, a new walk state was created -- get it
546147904Ssam             */
547147904Ssam            WalkState = AcpiDsGetCurrentWalkState (Thread);
548147904Ssam            continue;
549147904Ssam        }
550172686Smlaier        else if (Status == AE_CTRL_TERMINATE)
551172686Smlaier        {
552172686Smlaier            Status = AE_OK;
553147904Ssam        }
554147904Ssam        else if ((Status != AE_OK) && (WalkState->MethodDesc))
55575118Sfenner        {
55675118Sfenner            /* Either the method parse or actual execution failed */
55775118Sfenner
558127675Sbms            ACPI_ERROR_METHOD ("Method parse/execution failed",
559147904Ssam                WalkState->MethodNode, NULL, Status);
560147904Ssam
561147904Ssam            /* Check for possible multi-thread reentrancy problem */
562147904Ssam
563147904Ssam            if ((Status == AE_ALREADY_EXISTS) &&
564147904Ssam                (!(WalkState->MethodDesc->Method.InfoFlags &
56575118Sfenner                    ACPI_METHOD_SERIALIZED)))
56675118Sfenner            {
56775118Sfenner                /*
56875118Sfenner                 * Method is not serialized and tried to create an object
569127675Sbms                 * twice. The probable cause is that the method cannot
570147904Ssam                 * handle reentrancy. Mark as "pending serialized" now, and
571127675Sbms                 * then mark "serialized" when the last thread exits.
572127675Sbms                 */
57375118Sfenner                WalkState->MethodDesc->Method.InfoFlags |=
57475118Sfenner                    ACPI_METHOD_SERIALIZED_PENDING;
57556896Sfenner            }
576127675Sbms        }
577127675Sbms
578127675Sbms        /* We are done with this walk, move on to the parent if any */
579127675Sbms
580147904Ssam        WalkState = AcpiDsPopWalkState (Thread);
58156896Sfenner
58238638Sthepish        /* Reset the current scope to the beginning of scope stack */
583127675Sbms
584127675Sbms        AcpiDsScopeStackClear (WalkState);
585127675Sbms
586127675Sbms        /*
58738638Sthepish         * If we just returned from the execution of a control method or if we
58832149Spst         * encountered an error during the method parse phase, there's lots of
58938638Sthepish         * cleanup to do
59038638Sthepish         */
59175118Sfenner        if (((WalkState->ParseFlags & ACPI_PARSE_MODE_MASK) ==
59238638Sthepish            ACPI_PARSE_EXECUTE) ||
59375118Sfenner            (ACPI_FAILURE (Status)))
59475118Sfenner        {
59575118Sfenner            AcpiDsTerminateControlMethod (WalkState->MethodDesc, WalkState);
59675118Sfenner        }
597127675Sbms
59875118Sfenner        /* Delete this walk state and all linked control states */
59975118Sfenner
60075118Sfenner        AcpiPsCleanupScope (&WalkState->ParserState);
60175118Sfenner        PreviousWalkState = WalkState;
602147904Ssam
603147904Ssam        ACPI_DEBUG_PRINT ((ACPI_DB_PARSE,
604147904Ssam            "ReturnValue=%p, ImplicitValue=%p State=%p\n",
605147904Ssam            WalkState->ReturnDesc, WalkState->ImplicitReturnObj, WalkState));
606147904Ssam
607147904Ssam        /* Check if we have restarted a preempted walk */
608147904Ssam
60956896Sfenner        WalkState = AcpiDsGetCurrentWalkState (Thread);
610147904Ssam        if (WalkState)
61175118Sfenner        {
612147904Ssam            if (ACPI_SUCCESS (Status))
61375118Sfenner            {
61475118Sfenner                /*
61538638Sthepish                 * There is another walk state, restart it.
61656896Sfenner                 * If the method return value is not used by the parent,
61775118Sfenner                 * The object is deleted
61875118Sfenner                 */
619127675Sbms                if (!PreviousWalkState->ReturnDesc)
620147904Ssam                {
621146778Ssam                    /*
622146778Ssam                     * In slack mode execution, if there is no return value
62375118Sfenner                     * we should implicitly return zero (0) as a default value.
624127675Sbms                     */
625146778Ssam                    if (AcpiGbl_EnableInterpreterSlack &&
626146778Ssam                        !PreviousWalkState->ImplicitReturnObj)
62775118Sfenner                    {
628127675Sbms                        PreviousWalkState->ImplicitReturnObj =
62975118Sfenner                            AcpiUtCreateIntegerObject ((UINT64) 0);
63075118Sfenner                        if (!PreviousWalkState->ImplicitReturnObj)
63175118Sfenner                        {
63275118Sfenner                            return_ACPI_STATUS (AE_NO_MEMORY);
63375118Sfenner                        }
63456896Sfenner                    }
635127675Sbms
636127675Sbms                    /* Restart the calling control method */
637147904Ssam
638127675Sbms                    Status = AcpiDsRestartControlMethod (WalkState,
63956896Sfenner                        PreviousWalkState->ImplicitReturnObj);
64075118Sfenner                }
641127675Sbms                else
642127675Sbms                {
643147904Ssam                    /*
644127675Sbms                     * We have a valid return value, delete any implicit
64575118Sfenner                     * return value.
64656896Sfenner                     */
64756896Sfenner                    AcpiDsClearImplicitReturn (PreviousWalkState);
648127675Sbms
649147904Ssam                    Status = AcpiDsRestartControlMethod (WalkState,
650146778Ssam                        PreviousWalkState->ReturnDesc);
651127675Sbms                }
652127675Sbms                if (ACPI_SUCCESS (Status))
653127675Sbms                {
654146778Ssam                    WalkState->WalkType |= ACPI_WALK_METHOD_RESTART;
655127675Sbms                }
656146778Ssam            }
657127675Sbms            else
658127675Sbms            {
659127675Sbms                /* On error, delete any return object or implicit return */
660146778Ssam
661127675Sbms                AcpiUtRemoveReference (PreviousWalkState->ReturnDesc);
662146778Ssam                AcpiDsClearImplicitReturn (PreviousWalkState);
663127675Sbms            }
66456896Sfenner        }
66556896Sfenner
66656896Sfenner        /*
66756896Sfenner         * Just completed a 1st-level method, save the final internal return
668127675Sbms         * value (if any)
669127675Sbms         */
67056896Sfenner        else if (PreviousWalkState->CallerReturnDesc)
67156896Sfenner        {
67256896Sfenner            if (PreviousWalkState->ImplicitReturnObj)
67356896Sfenner            {
67456896Sfenner                *(PreviousWalkState->CallerReturnDesc) =
67556896Sfenner                    PreviousWalkState->ImplicitReturnObj;
676127675Sbms            }
677127675Sbms            else
678147904Ssam            {
679127675Sbms                 /* NULL if no return value */
68056896Sfenner
68156896Sfenner                *(PreviousWalkState->CallerReturnDesc) =
68256896Sfenner                    PreviousWalkState->ReturnDesc;
68356896Sfenner            }
68456896Sfenner        }
68575118Sfenner        else
686127675Sbms        {
687127675Sbms            if (PreviousWalkState->ReturnDesc)
688147904Ssam            {
689127675Sbms                /* Caller doesn't want it, must delete it */
69075118Sfenner
69175118Sfenner                AcpiUtRemoveReference (PreviousWalkState->ReturnDesc);
69275118Sfenner            }
69375118Sfenner            if (PreviousWalkState->ImplicitReturnObj)
694127675Sbms            {
695147904Ssam                /* Caller doesn't want it, must delete it */
696147904Ssam
697147904Ssam                AcpiUtRemoveReference (PreviousWalkState->ImplicitReturnObj);
69875118Sfenner            }
69975118Sfenner        }
700127675Sbms
701127675Sbms        AcpiDsDeleteWalkState (PreviousWalkState);
702147904Ssam    }
703127675Sbms
70475118Sfenner    /* Normal exit */
70575118Sfenner
70675118Sfenner    AcpiExReleaseAllMutexes (Thread);
70775118Sfenner    AcpiUtDeleteGenericState (ACPI_CAST_PTR (ACPI_GENERIC_STATE, Thread));
708127675Sbms    AcpiGbl_CurrentWalkList = PrevWalkList;
70975118Sfenner    return_ACPI_STATUS (Status);
71075118Sfenner}
711147904Ssam