xref: /titanic_50/usr/src/uts/intel/io/acpica/parser/psloop.c (revision 385cc6b4ad1792caef3f84eb61eed3f27085801f)
1db2bae30SDana Myers /******************************************************************************
2db2bae30SDana Myers  *
3db2bae30SDana Myers  * Module Name: psloop - Main AML parse loop
4db2bae30SDana Myers  *
5db2bae30SDana Myers  *****************************************************************************/
6db2bae30SDana Myers 
726f3cdf0SGordon Ross /*
8*385cc6b4SJerry Jelinek  * Copyright (C) 2000 - 2016, Intel Corp.
9db2bae30SDana Myers  * All rights reserved.
10db2bae30SDana Myers  *
1126f3cdf0SGordon Ross  * Redistribution and use in source and binary forms, with or without
1226f3cdf0SGordon Ross  * modification, are permitted provided that the following conditions
1326f3cdf0SGordon Ross  * are met:
1426f3cdf0SGordon Ross  * 1. Redistributions of source code must retain the above copyright
1526f3cdf0SGordon Ross  *    notice, this list of conditions, and the following disclaimer,
1626f3cdf0SGordon Ross  *    without modification.
1726f3cdf0SGordon Ross  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
1826f3cdf0SGordon Ross  *    substantially similar to the "NO WARRANTY" disclaimer below
1926f3cdf0SGordon Ross  *    ("Disclaimer") and any redistribution must be conditioned upon
2026f3cdf0SGordon Ross  *    including a substantially similar Disclaimer requirement for further
2126f3cdf0SGordon Ross  *    binary redistribution.
2226f3cdf0SGordon Ross  * 3. Neither the names of the above-listed copyright holders nor the names
2326f3cdf0SGordon Ross  *    of any contributors may be used to endorse or promote products derived
2426f3cdf0SGordon Ross  *    from this software without specific prior written permission.
25db2bae30SDana Myers  *
2626f3cdf0SGordon Ross  * Alternatively, this software may be distributed under the terms of the
2726f3cdf0SGordon Ross  * GNU General Public License ("GPL") version 2 as published by the Free
2826f3cdf0SGordon Ross  * Software Foundation.
29db2bae30SDana Myers  *
3026f3cdf0SGordon Ross  * NO WARRANTY
3126f3cdf0SGordon Ross  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
3226f3cdf0SGordon Ross  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
3326f3cdf0SGordon Ross  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
3426f3cdf0SGordon Ross  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
3526f3cdf0SGordon Ross  * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
3626f3cdf0SGordon Ross  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3726f3cdf0SGordon Ross  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3826f3cdf0SGordon Ross  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
3926f3cdf0SGordon Ross  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
4026f3cdf0SGordon Ross  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
4126f3cdf0SGordon Ross  * POSSIBILITY OF SUCH DAMAGES.
4226f3cdf0SGordon Ross  */
43db2bae30SDana Myers 
44db2bae30SDana Myers /*
45db2bae30SDana Myers  * Parse the AML and build an operation tree as most interpreters, (such as
46db2bae30SDana Myers  * Perl) do. Parsing is done by hand rather than with a YACC generated parser
47db2bae30SDana Myers  * to tightly constrain stack and dynamic memory usage. Parsing is kept
48db2bae30SDana Myers  * flexible and the code fairly compact by parsing based on a list of AML
49db2bae30SDana Myers  * opcode templates in AmlOpInfo[].
50db2bae30SDana Myers  */
51db2bae30SDana Myers 
52db2bae30SDana Myers #include "acpi.h"
53aa2aa9a6SDana Myers #include "accommon.h"
54*385cc6b4SJerry Jelinek #include "acinterp.h"
55db2bae30SDana Myers #include "acparser.h"
56db2bae30SDana Myers #include "acdispat.h"
57db2bae30SDana Myers #include "amlcode.h"
58db2bae30SDana Myers 
59db2bae30SDana Myers #define _COMPONENT          ACPI_PARSER
60db2bae30SDana Myers         ACPI_MODULE_NAME    ("psloop")
61db2bae30SDana Myers 
62db2bae30SDana Myers 
63db2bae30SDana Myers /* Local prototypes */
64db2bae30SDana Myers 
65db2bae30SDana Myers static ACPI_STATUS
66db2bae30SDana Myers AcpiPsGetArguments (
67db2bae30SDana Myers     ACPI_WALK_STATE         *WalkState,
68db2bae30SDana Myers     UINT8                   *AmlOpStart,
69db2bae30SDana Myers     ACPI_PARSE_OBJECT       *Op);
70db2bae30SDana Myers 
7157190917SDana Myers static void
7257190917SDana Myers AcpiPsLinkModuleCode (
7357190917SDana Myers     ACPI_PARSE_OBJECT       *ParentOp,
7457190917SDana Myers     UINT8                   *AmlStart,
7557190917SDana Myers     UINT32                  AmlLength,
7657190917SDana Myers     ACPI_OWNER_ID           OwnerId);
7757190917SDana Myers 
78db2bae30SDana Myers 
79db2bae30SDana Myers /*******************************************************************************
80db2bae30SDana Myers  *
81db2bae30SDana Myers  * FUNCTION:    AcpiPsGetArguments
82db2bae30SDana Myers  *
83db2bae30SDana Myers  * PARAMETERS:  WalkState           - Current state
84db2bae30SDana Myers  *              AmlOpStart          - Op start in AML
85db2bae30SDana Myers  *              Op                  - Current Op
86db2bae30SDana Myers  *
87db2bae30SDana Myers  * RETURN:      Status
88db2bae30SDana Myers  *
89db2bae30SDana Myers  * DESCRIPTION: Get arguments for passed Op.
90db2bae30SDana Myers  *
91db2bae30SDana Myers  ******************************************************************************/
92db2bae30SDana Myers 
93db2bae30SDana Myers static ACPI_STATUS
AcpiPsGetArguments(ACPI_WALK_STATE * WalkState,UINT8 * AmlOpStart,ACPI_PARSE_OBJECT * Op)94db2bae30SDana Myers AcpiPsGetArguments (
95db2bae30SDana Myers     ACPI_WALK_STATE         *WalkState,
96db2bae30SDana Myers     UINT8                   *AmlOpStart,
97db2bae30SDana Myers     ACPI_PARSE_OBJECT       *Op)
98db2bae30SDana Myers {
99db2bae30SDana Myers     ACPI_STATUS             Status = AE_OK;
100db2bae30SDana Myers     ACPI_PARSE_OBJECT       *Arg = NULL;
10157190917SDana Myers     const ACPI_OPCODE_INFO  *OpInfo;
102db2bae30SDana Myers 
103db2bae30SDana Myers 
104db2bae30SDana Myers     ACPI_FUNCTION_TRACE_PTR (PsGetArguments, WalkState);
105db2bae30SDana Myers 
106db2bae30SDana Myers 
107db2bae30SDana Myers     switch (Op->Common.AmlOpcode)
108db2bae30SDana Myers     {
109db2bae30SDana Myers     case AML_BYTE_OP:       /* AML_BYTEDATA_ARG */
110db2bae30SDana Myers     case AML_WORD_OP:       /* AML_WORDDATA_ARG */
111db2bae30SDana Myers     case AML_DWORD_OP:      /* AML_DWORDATA_ARG */
112db2bae30SDana Myers     case AML_QWORD_OP:      /* AML_QWORDATA_ARG */
113db2bae30SDana Myers     case AML_STRING_OP:     /* AML_ASCIICHARLIST_ARG */
114db2bae30SDana Myers 
115db2bae30SDana Myers         /* Fill in constant or string argument directly */
116db2bae30SDana Myers 
117db2bae30SDana Myers         AcpiPsGetNextSimpleArg (&(WalkState->ParserState),
118db2bae30SDana Myers             GET_CURRENT_ARG_TYPE (WalkState->ArgTypes), Op);
119db2bae30SDana Myers         break;
120db2bae30SDana Myers 
121db2bae30SDana Myers     case AML_INT_NAMEPATH_OP:   /* AML_NAMESTRING_ARG */
122db2bae30SDana Myers 
123*385cc6b4SJerry Jelinek         Status = AcpiPsGetNextNamepath (WalkState,
124*385cc6b4SJerry Jelinek             &(WalkState->ParserState), Op, ACPI_POSSIBLE_METHOD_CALL);
125db2bae30SDana Myers         if (ACPI_FAILURE (Status))
126db2bae30SDana Myers         {
127db2bae30SDana Myers             return_ACPI_STATUS (Status);
128db2bae30SDana Myers         }
129db2bae30SDana Myers 
130db2bae30SDana Myers         WalkState->ArgTypes = 0;
131db2bae30SDana Myers         break;
132db2bae30SDana Myers 
133db2bae30SDana Myers     default:
134db2bae30SDana Myers         /*
135db2bae30SDana Myers          * Op is not a constant or string, append each argument to the Op
136db2bae30SDana Myers          */
137*385cc6b4SJerry Jelinek         while (GET_CURRENT_ARG_TYPE (WalkState->ArgTypes) &&
138*385cc6b4SJerry Jelinek             !WalkState->ArgCount)
139db2bae30SDana Myers         {
140*385cc6b4SJerry Jelinek             WalkState->Aml = WalkState->ParserState.Aml;
141db2bae30SDana Myers 
142db2bae30SDana Myers             Status = AcpiPsGetNextArg (WalkState, &(WalkState->ParserState),
143db2bae30SDana Myers                 GET_CURRENT_ARG_TYPE (WalkState->ArgTypes), &Arg);
144db2bae30SDana Myers             if (ACPI_FAILURE (Status))
145db2bae30SDana Myers             {
146db2bae30SDana Myers                 return_ACPI_STATUS (Status);
147db2bae30SDana Myers             }
148db2bae30SDana Myers 
149db2bae30SDana Myers             if (Arg)
150db2bae30SDana Myers             {
151db2bae30SDana Myers                 AcpiPsAppendArg (Op, Arg);
152db2bae30SDana Myers             }
153db2bae30SDana Myers 
154db2bae30SDana Myers             INCREMENT_ARG_LIST (WalkState->ArgTypes);
155db2bae30SDana Myers         }
156db2bae30SDana Myers 
157db2bae30SDana Myers 
15857190917SDana Myers         /*
15957190917SDana Myers          * Handle executable code at "module-level". This refers to
16057190917SDana Myers          * executable opcodes that appear outside of any control method.
16157190917SDana Myers          */
16257190917SDana Myers         if ((WalkState->PassNumber <= ACPI_IMODE_LOAD_PASS2) &&
163db2bae30SDana Myers             ((WalkState->ParseFlags & ACPI_PARSE_DISASSEMBLE) == 0))
164db2bae30SDana Myers         {
165db2bae30SDana Myers             /*
166db2bae30SDana Myers              * We want to skip If/Else/While constructs during Pass1 because we
167db2bae30SDana Myers              * want to actually conditionally execute the code during Pass2.
168db2bae30SDana Myers              *
169db2bae30SDana Myers              * Except for disassembly, where we always want to walk the
170db2bae30SDana Myers              * If/Else/While packages
171db2bae30SDana Myers              */
172db2bae30SDana Myers             switch (Op->Common.AmlOpcode)
173db2bae30SDana Myers             {
174db2bae30SDana Myers             case AML_IF_OP:
175db2bae30SDana Myers             case AML_ELSE_OP:
176db2bae30SDana Myers             case AML_WHILE_OP:
17757190917SDana Myers                 /*
17857190917SDana Myers                  * Currently supported module-level opcodes are:
17957190917SDana Myers                  * IF/ELSE/WHILE. These appear to be the most common,
18057190917SDana Myers                  * and easiest to support since they open an AML
18157190917SDana Myers                  * package.
18257190917SDana Myers                  */
18357190917SDana Myers                 if (WalkState->PassNumber == ACPI_IMODE_LOAD_PASS1)
18457190917SDana Myers                 {
18557190917SDana Myers                     AcpiPsLinkModuleCode (Op->Common.Parent, AmlOpStart,
18657190917SDana Myers                         (UINT32) (WalkState->ParserState.PkgEnd - AmlOpStart),
18757190917SDana Myers                         WalkState->OwnerId);
18857190917SDana Myers                 }
18957190917SDana Myers 
190db2bae30SDana Myers                 ACPI_DEBUG_PRINT ((ACPI_DB_PARSE,
191db2bae30SDana Myers                     "Pass1: Skipping an If/Else/While body\n"));
192db2bae30SDana Myers 
193db2bae30SDana Myers                 /* Skip body of if/else/while in pass 1 */
194db2bae30SDana Myers 
195db2bae30SDana Myers                 WalkState->ParserState.Aml = WalkState->ParserState.PkgEnd;
196db2bae30SDana Myers                 WalkState->ArgCount = 0;
197db2bae30SDana Myers                 break;
198db2bae30SDana Myers 
199db2bae30SDana Myers             default:
20057190917SDana Myers                 /*
20157190917SDana Myers                  * Check for an unsupported executable opcode at module
20257190917SDana Myers                  * level. We must be in PASS1, the parent must be a SCOPE,
20357190917SDana Myers                  * The opcode class must be EXECUTE, and the opcode must
20457190917SDana Myers                  * not be an argument to another opcode.
20557190917SDana Myers                  */
20657190917SDana Myers                 if ((WalkState->PassNumber == ACPI_IMODE_LOAD_PASS1) &&
20757190917SDana Myers                     (Op->Common.Parent->Common.AmlOpcode == AML_SCOPE_OP))
20857190917SDana Myers                 {
20957190917SDana Myers                     OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode);
21057190917SDana Myers                     if ((OpInfo->Class == AML_CLASS_EXECUTE) &&
21157190917SDana Myers                         (!Arg))
21257190917SDana Myers                     {
21357190917SDana Myers                         ACPI_WARNING ((AE_INFO,
214*385cc6b4SJerry Jelinek                             "Unsupported module-level executable opcode "
215*385cc6b4SJerry Jelinek                             "0x%.2X at table offset 0x%.4X",
21657190917SDana Myers                             Op->Common.AmlOpcode,
21757190917SDana Myers                             (UINT32) (ACPI_PTR_DIFF (AmlOpStart,
21857190917SDana Myers                                 WalkState->ParserState.AmlStart) +
21957190917SDana Myers                                 sizeof (ACPI_TABLE_HEADER))));
22057190917SDana Myers                     }
22157190917SDana Myers                 }
222db2bae30SDana Myers                 break;
223db2bae30SDana Myers             }
224db2bae30SDana Myers         }
22557190917SDana Myers 
22657190917SDana Myers         /* Special processing for certain opcodes */
227db2bae30SDana Myers 
228db2bae30SDana Myers         switch (Op->Common.AmlOpcode)
229db2bae30SDana Myers         {
230db2bae30SDana Myers         case AML_METHOD_OP:
231db2bae30SDana Myers             /*
232db2bae30SDana Myers              * Skip parsing of control method because we don't have enough
233db2bae30SDana Myers              * info in the first pass to parse it correctly.
234db2bae30SDana Myers              *
235db2bae30SDana Myers              * Save the length and address of the body
236db2bae30SDana Myers              */
237db2bae30SDana Myers             Op->Named.Data = WalkState->ParserState.Aml;
238db2bae30SDana Myers             Op->Named.Length = (UINT32)
239db2bae30SDana Myers                 (WalkState->ParserState.PkgEnd - WalkState->ParserState.Aml);
240db2bae30SDana Myers 
241db2bae30SDana Myers             /* Skip body of method */
242db2bae30SDana Myers 
243db2bae30SDana Myers             WalkState->ParserState.Aml = WalkState->ParserState.PkgEnd;
244db2bae30SDana Myers             WalkState->ArgCount = 0;
245db2bae30SDana Myers             break;
246db2bae30SDana Myers 
247db2bae30SDana Myers         case AML_BUFFER_OP:
248db2bae30SDana Myers         case AML_PACKAGE_OP:
249db2bae30SDana Myers         case AML_VAR_PACKAGE_OP:
250db2bae30SDana Myers 
251db2bae30SDana Myers             if ((Op->Common.Parent) &&
252db2bae30SDana Myers                 (Op->Common.Parent->Common.AmlOpcode == AML_NAME_OP) &&
253db2bae30SDana Myers                 (WalkState->PassNumber <= ACPI_IMODE_LOAD_PASS2))
254db2bae30SDana Myers             {
255db2bae30SDana Myers                 /*
256db2bae30SDana Myers                  * Skip parsing of Buffers and Packages because we don't have
257db2bae30SDana Myers                  * enough info in the first pass to parse them correctly.
258db2bae30SDana Myers                  */
259db2bae30SDana Myers                 Op->Named.Data = AmlOpStart;
260db2bae30SDana Myers                 Op->Named.Length = (UINT32)
261db2bae30SDana Myers                     (WalkState->ParserState.PkgEnd - AmlOpStart);
262db2bae30SDana Myers 
263db2bae30SDana Myers                 /* Skip body */
264db2bae30SDana Myers 
265db2bae30SDana Myers                 WalkState->ParserState.Aml = WalkState->ParserState.PkgEnd;
266db2bae30SDana Myers                 WalkState->ArgCount = 0;
267db2bae30SDana Myers             }
268db2bae30SDana Myers             break;
269db2bae30SDana Myers 
270db2bae30SDana Myers         case AML_WHILE_OP:
271db2bae30SDana Myers 
272db2bae30SDana Myers             if (WalkState->ControlState)
273db2bae30SDana Myers             {
274db2bae30SDana Myers                 WalkState->ControlState->Control.PackageEnd =
275db2bae30SDana Myers                     WalkState->ParserState.PkgEnd;
276db2bae30SDana Myers             }
277db2bae30SDana Myers             break;
278db2bae30SDana Myers 
279db2bae30SDana Myers         default:
280db2bae30SDana Myers 
281db2bae30SDana Myers             /* No action for all other opcodes */
282*385cc6b4SJerry Jelinek 
283db2bae30SDana Myers             break;
284db2bae30SDana Myers         }
285db2bae30SDana Myers 
286db2bae30SDana Myers         break;
287db2bae30SDana Myers     }
288db2bae30SDana Myers 
289db2bae30SDana Myers     return_ACPI_STATUS (AE_OK);
290db2bae30SDana Myers }
291db2bae30SDana Myers 
292db2bae30SDana Myers 
293db2bae30SDana Myers /*******************************************************************************
294db2bae30SDana Myers  *
29557190917SDana Myers  * FUNCTION:    AcpiPsLinkModuleCode
29657190917SDana Myers  *
29757190917SDana Myers  * PARAMETERS:  ParentOp            - Parent parser op
29857190917SDana Myers  *              AmlStart            - Pointer to the AML
29957190917SDana Myers  *              AmlLength           - Length of executable AML
30057190917SDana Myers  *              OwnerId             - OwnerId of module level code
30157190917SDana Myers  *
30257190917SDana Myers  * RETURN:      None.
30357190917SDana Myers  *
30457190917SDana Myers  * DESCRIPTION: Wrap the module-level code with a method object and link the
30557190917SDana Myers  *              object to the global list. Note, the mutex field of the method
30657190917SDana Myers  *              object is used to link multiple module-level code objects.
30757190917SDana Myers  *
30857190917SDana Myers  ******************************************************************************/
30957190917SDana Myers 
31057190917SDana Myers static void
AcpiPsLinkModuleCode(ACPI_PARSE_OBJECT * ParentOp,UINT8 * AmlStart,UINT32 AmlLength,ACPI_OWNER_ID OwnerId)31157190917SDana Myers AcpiPsLinkModuleCode (
31257190917SDana Myers     ACPI_PARSE_OBJECT       *ParentOp,
31357190917SDana Myers     UINT8                   *AmlStart,
31457190917SDana Myers     UINT32                  AmlLength,
31557190917SDana Myers     ACPI_OWNER_ID           OwnerId)
31657190917SDana Myers {
31757190917SDana Myers     ACPI_OPERAND_OBJECT     *Prev;
31857190917SDana Myers     ACPI_OPERAND_OBJECT     *Next;
31957190917SDana Myers     ACPI_OPERAND_OBJECT     *MethodObj;
32057190917SDana Myers     ACPI_NAMESPACE_NODE     *ParentNode;
32157190917SDana Myers 
32257190917SDana Myers 
323*385cc6b4SJerry Jelinek     ACPI_FUNCTION_TRACE (PsLinkModuleCode);
324*385cc6b4SJerry Jelinek 
325*385cc6b4SJerry Jelinek 
32657190917SDana Myers     /* Get the tail of the list */
32757190917SDana Myers 
32857190917SDana Myers     Prev = Next = AcpiGbl_ModuleCodeList;
32957190917SDana Myers     while (Next)
33057190917SDana Myers     {
33157190917SDana Myers         Prev = Next;
33257190917SDana Myers         Next = Next->Method.Mutex;
33357190917SDana Myers     }
33457190917SDana Myers 
33557190917SDana Myers     /*
33657190917SDana Myers      * Insert the module level code into the list. Merge it if it is
33757190917SDana Myers      * adjacent to the previous element.
33857190917SDana Myers      */
33957190917SDana Myers     if (!Prev ||
34057190917SDana Myers        ((Prev->Method.AmlStart + Prev->Method.AmlLength) != AmlStart))
34157190917SDana Myers     {
34257190917SDana Myers         /* Create, initialize, and link a new temporary method object */
34357190917SDana Myers 
34457190917SDana Myers         MethodObj = AcpiUtCreateInternalObject (ACPI_TYPE_METHOD);
34557190917SDana Myers         if (!MethodObj)
34657190917SDana Myers         {
347*385cc6b4SJerry Jelinek             return_VOID;
34857190917SDana Myers         }
34957190917SDana Myers 
350*385cc6b4SJerry Jelinek         ACPI_DEBUG_PRINT ((ACPI_DB_PARSE,
351*385cc6b4SJerry Jelinek             "Create/Link new code block: %p\n", MethodObj));
352*385cc6b4SJerry Jelinek 
35357190917SDana Myers         if (ParentOp->Common.Node)
35457190917SDana Myers         {
35557190917SDana Myers             ParentNode = ParentOp->Common.Node;
35657190917SDana Myers         }
35757190917SDana Myers         else
35857190917SDana Myers         {
35957190917SDana Myers             ParentNode = AcpiGbl_RootNode;
36057190917SDana Myers         }
36157190917SDana Myers 
36257190917SDana Myers         MethodObj->Method.AmlStart = AmlStart;
36357190917SDana Myers         MethodObj->Method.AmlLength = AmlLength;
36457190917SDana Myers         MethodObj->Method.OwnerId = OwnerId;
36526f3cdf0SGordon Ross         MethodObj->Method.InfoFlags |= ACPI_METHOD_MODULE_LEVEL;
36657190917SDana Myers 
36757190917SDana Myers         /*
36857190917SDana Myers          * Save the parent node in NextObject. This is cheating, but we
36957190917SDana Myers          * don't want to expand the method object.
37057190917SDana Myers          */
37157190917SDana Myers         MethodObj->Method.NextObject =
37257190917SDana Myers             ACPI_CAST_PTR (ACPI_OPERAND_OBJECT, ParentNode);
37357190917SDana Myers 
37457190917SDana Myers         if (!Prev)
37557190917SDana Myers         {
37657190917SDana Myers             AcpiGbl_ModuleCodeList = MethodObj;
37757190917SDana Myers         }
37857190917SDana Myers         else
37957190917SDana Myers         {
38057190917SDana Myers             Prev->Method.Mutex = MethodObj;
38157190917SDana Myers         }
38257190917SDana Myers     }
38357190917SDana Myers     else
38457190917SDana Myers     {
385*385cc6b4SJerry Jelinek         ACPI_DEBUG_PRINT ((ACPI_DB_PARSE,
386*385cc6b4SJerry Jelinek             "Appending to existing code block: %p\n", Prev));
387*385cc6b4SJerry Jelinek 
38857190917SDana Myers         Prev->Method.AmlLength += AmlLength;
38957190917SDana Myers     }
390*385cc6b4SJerry Jelinek 
391*385cc6b4SJerry Jelinek     return_VOID;
39257190917SDana Myers }
39357190917SDana Myers 
394db2bae30SDana Myers /*******************************************************************************
395db2bae30SDana Myers  *
396db2bae30SDana Myers  * FUNCTION:    AcpiPsParseLoop
397db2bae30SDana Myers  *
398db2bae30SDana Myers  * PARAMETERS:  WalkState           - Current state
399db2bae30SDana Myers  *
400db2bae30SDana Myers  * RETURN:      Status
401db2bae30SDana Myers  *
402db2bae30SDana Myers  * DESCRIPTION: Parse AML (pointed to by the current parser state) and return
403db2bae30SDana Myers  *              a tree of ops.
404db2bae30SDana Myers  *
405db2bae30SDana Myers  ******************************************************************************/
406db2bae30SDana Myers 
407db2bae30SDana Myers ACPI_STATUS
AcpiPsParseLoop(ACPI_WALK_STATE * WalkState)408db2bae30SDana Myers AcpiPsParseLoop (
409db2bae30SDana Myers     ACPI_WALK_STATE         *WalkState)
410db2bae30SDana Myers {
411db2bae30SDana Myers     ACPI_STATUS             Status = AE_OK;
412db2bae30SDana Myers     ACPI_PARSE_OBJECT       *Op = NULL;     /* current op */
413db2bae30SDana Myers     ACPI_PARSE_STATE        *ParserState;
414db2bae30SDana Myers     UINT8                   *AmlOpStart = NULL;
415db2bae30SDana Myers 
416db2bae30SDana Myers 
417db2bae30SDana Myers     ACPI_FUNCTION_TRACE_PTR (PsParseLoop, WalkState);
418db2bae30SDana Myers 
419db2bae30SDana Myers 
420db2bae30SDana Myers     if (WalkState->DescendingCallback == NULL)
421db2bae30SDana Myers     {
422db2bae30SDana Myers         return_ACPI_STATUS (AE_BAD_PARAMETER);
423db2bae30SDana Myers     }
424db2bae30SDana Myers 
425db2bae30SDana Myers     ParserState = &WalkState->ParserState;
426db2bae30SDana Myers     WalkState->ArgTypes = 0;
427db2bae30SDana Myers 
428db2bae30SDana Myers #if (!defined (ACPI_NO_METHOD_EXECUTION) && !defined (ACPI_CONSTANT_EVAL_ONLY))
429db2bae30SDana Myers 
430db2bae30SDana Myers     if (WalkState->WalkType & ACPI_WALK_METHOD_RESTART)
431db2bae30SDana Myers     {
432db2bae30SDana Myers         /* We are restarting a preempted control method */
433db2bae30SDana Myers 
434db2bae30SDana Myers         if (AcpiPsHasCompletedScope (ParserState))
435db2bae30SDana Myers         {
436db2bae30SDana Myers             /*
437db2bae30SDana Myers              * We must check if a predicate to an IF or WHILE statement
438db2bae30SDana Myers              * was just completed
439db2bae30SDana Myers              */
440db2bae30SDana Myers             if ((ParserState->Scope->ParseScope.Op) &&
441db2bae30SDana Myers                ((ParserState->Scope->ParseScope.Op->Common.AmlOpcode == AML_IF_OP) ||
442db2bae30SDana Myers                 (ParserState->Scope->ParseScope.Op->Common.AmlOpcode == AML_WHILE_OP)) &&
443db2bae30SDana Myers                 (WalkState->ControlState) &&
444db2bae30SDana Myers                 (WalkState->ControlState->Common.State ==
445db2bae30SDana Myers                     ACPI_CONTROL_PREDICATE_EXECUTING))
446db2bae30SDana Myers             {
447db2bae30SDana Myers                 /*
448db2bae30SDana Myers                  * A predicate was just completed, get the value of the
449db2bae30SDana Myers                  * predicate and branch based on that value
450db2bae30SDana Myers                  */
451db2bae30SDana Myers                 WalkState->Op = NULL;
452db2bae30SDana Myers                 Status = AcpiDsGetPredicateValue (WalkState, ACPI_TO_POINTER (TRUE));
453db2bae30SDana Myers                 if (ACPI_FAILURE (Status) &&
454db2bae30SDana Myers                     ((Status & AE_CODE_MASK) != AE_CODE_CONTROL))
455db2bae30SDana Myers                 {
456db2bae30SDana Myers                     if (Status == AE_AML_NO_RETURN_VALUE)
457db2bae30SDana Myers                     {
458db2bae30SDana Myers                         ACPI_EXCEPTION ((AE_INFO, Status,
459db2bae30SDana Myers                             "Invoked method did not return a value"));
460db2bae30SDana Myers                     }
461db2bae30SDana Myers 
462db2bae30SDana Myers                     ACPI_EXCEPTION ((AE_INFO, Status, "GetPredicate Failed"));
463db2bae30SDana Myers                     return_ACPI_STATUS (Status);
464db2bae30SDana Myers                 }
465db2bae30SDana Myers 
466db2bae30SDana Myers                 Status = AcpiPsNextParseState (WalkState, Op, Status);
467db2bae30SDana Myers             }
468db2bae30SDana Myers 
469db2bae30SDana Myers             AcpiPsPopScope (ParserState, &Op,
470db2bae30SDana Myers                 &WalkState->ArgTypes, &WalkState->ArgCount);
471db2bae30SDana Myers             ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "Popped scope, Op=%p\n", Op));
472db2bae30SDana Myers         }
473db2bae30SDana Myers         else if (WalkState->PrevOp)
474db2bae30SDana Myers         {
475db2bae30SDana Myers             /* We were in the middle of an op */
476db2bae30SDana Myers 
477db2bae30SDana Myers             Op = WalkState->PrevOp;
478db2bae30SDana Myers             WalkState->ArgTypes = WalkState->PrevArgTypes;
479db2bae30SDana Myers         }
480db2bae30SDana Myers     }
481db2bae30SDana Myers #endif
482db2bae30SDana Myers 
483db2bae30SDana Myers     /* Iterative parsing loop, while there is more AML to process: */
484db2bae30SDana Myers 
485db2bae30SDana Myers     while ((ParserState->Aml < ParserState->AmlEnd) || (Op))
486db2bae30SDana Myers     {
487db2bae30SDana Myers         AmlOpStart = ParserState->Aml;
488db2bae30SDana Myers         if (!Op)
489db2bae30SDana Myers         {
490db2bae30SDana Myers             Status = AcpiPsCreateOp (WalkState, AmlOpStart, &Op);
491db2bae30SDana Myers             if (ACPI_FAILURE (Status))
492db2bae30SDana Myers             {
493db2bae30SDana Myers                 if (Status == AE_CTRL_PARSE_CONTINUE)
494db2bae30SDana Myers                 {
495db2bae30SDana Myers                     continue;
496db2bae30SDana Myers                 }
497db2bae30SDana Myers 
498db2bae30SDana Myers                 if (Status == AE_CTRL_PARSE_PENDING)
499db2bae30SDana Myers                 {
500db2bae30SDana Myers                     Status = AE_OK;
501db2bae30SDana Myers                 }
502db2bae30SDana Myers 
503*385cc6b4SJerry Jelinek                 if (Status == AE_CTRL_TERMINATE)
504*385cc6b4SJerry Jelinek                 {
505*385cc6b4SJerry Jelinek                     return_ACPI_STATUS (Status);
506*385cc6b4SJerry Jelinek                 }
507*385cc6b4SJerry Jelinek 
508db2bae30SDana Myers                 Status = AcpiPsCompleteOp (WalkState, &Op, Status);
509db2bae30SDana Myers                 if (ACPI_FAILURE (Status))
510db2bae30SDana Myers                 {
511db2bae30SDana Myers                     return_ACPI_STATUS (Status);
512db2bae30SDana Myers                 }
513db2bae30SDana Myers 
514db2bae30SDana Myers                 continue;
515db2bae30SDana Myers             }
516db2bae30SDana Myers 
517*385cc6b4SJerry Jelinek             AcpiExStartTraceOpcode (Op, WalkState);
518db2bae30SDana Myers         }
519db2bae30SDana Myers 
520db2bae30SDana Myers 
521db2bae30SDana Myers         /*
522db2bae30SDana Myers          * Start ArgCount at zero because we don't know if there are
523db2bae30SDana Myers          * any args yet
524db2bae30SDana Myers          */
525db2bae30SDana Myers         WalkState->ArgCount  = 0;
526db2bae30SDana Myers 
527db2bae30SDana Myers         /* Are there any arguments that must be processed? */
528db2bae30SDana Myers 
529db2bae30SDana Myers         if (WalkState->ArgTypes)
530db2bae30SDana Myers         {
531db2bae30SDana Myers             /* Get arguments */
532db2bae30SDana Myers 
533db2bae30SDana Myers             Status = AcpiPsGetArguments (WalkState, AmlOpStart, Op);
534db2bae30SDana Myers             if (ACPI_FAILURE (Status))
535db2bae30SDana Myers             {
536db2bae30SDana Myers                 Status = AcpiPsCompleteOp (WalkState, &Op, Status);
537db2bae30SDana Myers                 if (ACPI_FAILURE (Status))
538db2bae30SDana Myers                 {
539db2bae30SDana Myers                     return_ACPI_STATUS (Status);
540db2bae30SDana Myers                 }
541db2bae30SDana Myers 
542db2bae30SDana Myers                 continue;
543db2bae30SDana Myers             }
544db2bae30SDana Myers         }
545db2bae30SDana Myers 
546db2bae30SDana Myers         /* Check for arguments that need to be processed */
547db2bae30SDana Myers 
548db2bae30SDana Myers         if (WalkState->ArgCount)
549db2bae30SDana Myers         {
550db2bae30SDana Myers             /*
551db2bae30SDana Myers              * There are arguments (complex ones), push Op and
552db2bae30SDana Myers              * prepare for argument
553db2bae30SDana Myers              */
554db2bae30SDana Myers             Status = AcpiPsPushScope (ParserState, Op,
555db2bae30SDana Myers                 WalkState->ArgTypes, WalkState->ArgCount);
556db2bae30SDana Myers             if (ACPI_FAILURE (Status))
557db2bae30SDana Myers             {
558db2bae30SDana Myers                 Status = AcpiPsCompleteOp (WalkState, &Op, Status);
559db2bae30SDana Myers                 if (ACPI_FAILURE (Status))
560db2bae30SDana Myers                 {
561db2bae30SDana Myers                     return_ACPI_STATUS (Status);
562db2bae30SDana Myers                 }
563db2bae30SDana Myers 
564db2bae30SDana Myers                 continue;
565db2bae30SDana Myers             }
566db2bae30SDana Myers 
567db2bae30SDana Myers             Op = NULL;
568db2bae30SDana Myers             continue;
569db2bae30SDana Myers         }
570db2bae30SDana Myers 
571db2bae30SDana Myers         /*
572db2bae30SDana Myers          * All arguments have been processed -- Op is complete,
573db2bae30SDana Myers          * prepare for next
574db2bae30SDana Myers          */
575db2bae30SDana Myers         WalkState->OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode);
576db2bae30SDana Myers         if (WalkState->OpInfo->Flags & AML_NAMED)
577db2bae30SDana Myers         {
578db2bae30SDana Myers             if (Op->Common.AmlOpcode == AML_REGION_OP ||
579db2bae30SDana Myers                 Op->Common.AmlOpcode == AML_DATA_REGION_OP)
580db2bae30SDana Myers             {
581db2bae30SDana Myers                 /*
582db2bae30SDana Myers                  * Skip parsing of control method or opregion body,
583db2bae30SDana Myers                  * because we don't have enough info in the first pass
584db2bae30SDana Myers                  * to parse them correctly.
585db2bae30SDana Myers                  *
586db2bae30SDana Myers                  * Completed parsing an OpRegion declaration, we now
587db2bae30SDana Myers                  * know the length.
588db2bae30SDana Myers                  */
589db2bae30SDana Myers                 Op->Named.Length = (UINT32) (ParserState->Aml - Op->Named.Data);
590db2bae30SDana Myers             }
591db2bae30SDana Myers         }
592db2bae30SDana Myers 
593db2bae30SDana Myers         if (WalkState->OpInfo->Flags & AML_CREATE)
594db2bae30SDana Myers         {
595db2bae30SDana Myers             /*
596db2bae30SDana Myers              * Backup to beginning of CreateXXXfield declaration (1 for
597db2bae30SDana Myers              * Opcode)
598db2bae30SDana Myers              *
599db2bae30SDana Myers              * BodyLength is unknown until we parse the body
600db2bae30SDana Myers              */
601db2bae30SDana Myers             Op->Named.Length = (UINT32) (ParserState->Aml - Op->Named.Data);
602db2bae30SDana Myers         }
603db2bae30SDana Myers 
604db2bae30SDana Myers         if (Op->Common.AmlOpcode == AML_BANK_FIELD_OP)
605db2bae30SDana Myers         {
606db2bae30SDana Myers             /*
607db2bae30SDana Myers              * Backup to beginning of BankField declaration
608db2bae30SDana Myers              *
609db2bae30SDana Myers              * BodyLength is unknown until we parse the body
610db2bae30SDana Myers              */
611db2bae30SDana Myers             Op->Named.Length = (UINT32) (ParserState->Aml - Op->Named.Data);
612db2bae30SDana Myers         }
613db2bae30SDana Myers 
614db2bae30SDana Myers         /* This op complete, notify the dispatcher */
615db2bae30SDana Myers 
616db2bae30SDana Myers         if (WalkState->AscendingCallback != NULL)
617db2bae30SDana Myers         {
618db2bae30SDana Myers             WalkState->Op = Op;
619db2bae30SDana Myers             WalkState->Opcode = Op->Common.AmlOpcode;
620db2bae30SDana Myers 
621db2bae30SDana Myers             Status = WalkState->AscendingCallback (WalkState);
622db2bae30SDana Myers             Status = AcpiPsNextParseState (WalkState, Op, Status);
623db2bae30SDana Myers             if (Status == AE_CTRL_PENDING)
624db2bae30SDana Myers             {
625db2bae30SDana Myers                 Status = AE_OK;
626db2bae30SDana Myers             }
627db2bae30SDana Myers         }
628db2bae30SDana Myers 
629db2bae30SDana Myers         Status = AcpiPsCompleteOp (WalkState, &Op, Status);
630db2bae30SDana Myers         if (ACPI_FAILURE (Status))
631db2bae30SDana Myers         {
632db2bae30SDana Myers             return_ACPI_STATUS (Status);
633db2bae30SDana Myers         }
634db2bae30SDana Myers 
635db2bae30SDana Myers     } /* while ParserState->Aml */
636db2bae30SDana Myers 
637db2bae30SDana Myers     Status = AcpiPsCompleteFinalOp (WalkState, Op, Status);
638db2bae30SDana Myers     return_ACPI_STATUS (Status);
639db2bae30SDana Myers }
640