1 /******************************************************************************
3 * Module Name: psloop - Main AML parse loop
5 *****************************************************************************/
8 * Copyright (C) 2000 - 2017, Intel Corp.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions, and the following disclaimer,
16 * without modification.
17 * 2. Redistributions in binary form must reproduce at minimum a disclaimer
18 * substantially similar to the "NO WARRANTY" disclaimer below
19 * ("Disclaimer") and any redistribution must be conditioned upon
20 * including a substantially similar Disclaimer requirement for further
21 * binary redistribution.
22 * 3. Neither the names of the above-listed copyright holders nor the names
23 * of any contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
26 * Alternatively, this software may be distributed under the terms of the
27 * GNU General Public License ("GPL") version 2 as published by the Free
28 * Software Foundation.
31 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
34 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
35 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
40 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41 * POSSIBILITY OF SUCH DAMAGES.
45 * Parse the AML and build an operation tree as most interpreters, (such as
46 * Perl) do. Parsing is done by hand rather than with a YACC generated parser
47 * to tightly constrain stack and dynamic memory usage. Parsing is kept
48 * flexible and the code fairly compact by parsing based on a list of AML
49 * opcode templates in AmlOpInfo[].
59 #define _COMPONENT ACPI_PARSER
60 ACPI_MODULE_NAME ("psloop")
63 /* Local prototypes */
67 ACPI_WALK_STATE
*WalkState
,
69 ACPI_PARSE_OBJECT
*Op
);
72 AcpiPsLinkModuleCode (
73 ACPI_PARSE_OBJECT
*ParentOp
,
76 ACPI_OWNER_ID OwnerId
);
79 /*******************************************************************************
81 * FUNCTION: AcpiPsGetArguments
83 * PARAMETERS: WalkState - Current state
84 * AmlOpStart - Op start in AML
89 * DESCRIPTION: Get arguments for passed Op.
91 ******************************************************************************/
95 ACPI_WALK_STATE
*WalkState
,
97 ACPI_PARSE_OBJECT
*Op
)
99 ACPI_STATUS Status
= AE_OK
;
100 ACPI_PARSE_OBJECT
*Arg
= NULL
;
101 const ACPI_OPCODE_INFO
*OpInfo
;
104 ACPI_FUNCTION_TRACE_PTR (PsGetArguments
, WalkState
);
107 ACPI_DEBUG_PRINT ((ACPI_DB_PARSE
,
108 "Get arguments for opcode [%s]\n", Op
->Common
.AmlOpName
));
110 switch (Op
->Common
.AmlOpcode
)
112 case AML_BYTE_OP
: /* AML_BYTEDATA_ARG */
113 case AML_WORD_OP
: /* AML_WORDDATA_ARG */
114 case AML_DWORD_OP
: /* AML_DWORDATA_ARG */
115 case AML_QWORD_OP
: /* AML_QWORDATA_ARG */
116 case AML_STRING_OP
: /* AML_ASCIICHARLIST_ARG */
118 /* Fill in constant or string argument directly */
120 AcpiPsGetNextSimpleArg (&(WalkState
->ParserState
),
121 GET_CURRENT_ARG_TYPE (WalkState
->ArgTypes
), Op
);
124 case AML_INT_NAMEPATH_OP
: /* AML_NAMESTRING_ARG */
126 Status
= AcpiPsGetNextNamepath (WalkState
,
127 &(WalkState
->ParserState
), Op
, ACPI_POSSIBLE_METHOD_CALL
);
128 if (ACPI_FAILURE (Status
))
130 return_ACPI_STATUS (Status
);
133 WalkState
->ArgTypes
= 0;
138 * Op is not a constant or string, append each argument to the Op
140 while (GET_CURRENT_ARG_TYPE (WalkState
->ArgTypes
) &&
141 !WalkState
->ArgCount
)
143 WalkState
->Aml
= WalkState
->ParserState
.Aml
;
145 Status
= AcpiPsGetNextArg (WalkState
, &(WalkState
->ParserState
),
146 GET_CURRENT_ARG_TYPE (WalkState
->ArgTypes
), &Arg
);
147 if (ACPI_FAILURE (Status
))
149 return_ACPI_STATUS (Status
);
154 AcpiPsAppendArg (Op
, Arg
);
157 INCREMENT_ARG_LIST (WalkState
->ArgTypes
);
162 * Handle executable code at "module-level". This refers to
163 * executable opcodes that appear outside of any control method.
165 if ((WalkState
->PassNumber
<= ACPI_IMODE_LOAD_PASS2
) &&
166 ((WalkState
->ParseFlags
& ACPI_PARSE_DISASSEMBLE
) == 0))
169 * We want to skip If/Else/While constructs during Pass1 because we
170 * want to actually conditionally execute the code during Pass2.
172 * Except for disassembly, where we always want to walk the
173 * If/Else/While packages
175 switch (Op
->Common
.AmlOpcode
)
181 * Currently supported module-level opcodes are:
182 * IF/ELSE/WHILE. These appear to be the most common,
183 * and easiest to support since they open an AML
186 if (WalkState
->PassNumber
== ACPI_IMODE_LOAD_PASS1
)
188 AcpiPsLinkModuleCode (Op
->Common
.Parent
, AmlOpStart
,
189 (UINT32
) (WalkState
->ParserState
.PkgEnd
- AmlOpStart
),
193 ACPI_DEBUG_PRINT ((ACPI_DB_PARSE
,
194 "Pass1: Skipping an If/Else/While body\n"));
196 /* Skip body of if/else/while in pass 1 */
198 WalkState
->ParserState
.Aml
= WalkState
->ParserState
.PkgEnd
;
199 WalkState
->ArgCount
= 0;
204 * Check for an unsupported executable opcode at module
205 * level. We must be in PASS1, the parent must be a SCOPE,
206 * The opcode class must be EXECUTE, and the opcode must
207 * not be an argument to another opcode.
209 if ((WalkState
->PassNumber
== ACPI_IMODE_LOAD_PASS1
) &&
210 (Op
->Common
.Parent
->Common
.AmlOpcode
== AML_SCOPE_OP
))
212 OpInfo
= AcpiPsGetOpcodeInfo (Op
->Common
.AmlOpcode
);
213 if ((OpInfo
->Class
== AML_CLASS_EXECUTE
) &&
216 ACPI_WARNING ((AE_INFO
,
217 "Unsupported module-level executable opcode "
218 "0x%.2X at table offset 0x%.4X",
219 Op
->Common
.AmlOpcode
,
220 (UINT32
) (ACPI_PTR_DIFF (AmlOpStart
,
221 WalkState
->ParserState
.AmlStart
) +
222 sizeof (ACPI_TABLE_HEADER
))));
229 /* Special processing for certain opcodes */
231 switch (Op
->Common
.AmlOpcode
)
235 * Skip parsing of control method because we don't have enough
236 * info in the first pass to parse it correctly.
238 * Save the length and address of the body
240 Op
->Named
.Data
= WalkState
->ParserState
.Aml
;
241 Op
->Named
.Length
= (UINT32
)
242 (WalkState
->ParserState
.PkgEnd
- WalkState
->ParserState
.Aml
);
244 /* Skip body of method */
246 WalkState
->ParserState
.Aml
= WalkState
->ParserState
.PkgEnd
;
247 WalkState
->ArgCount
= 0;
252 case AML_VAR_PACKAGE_OP
:
254 if ((Op
->Common
.Parent
) &&
255 (Op
->Common
.Parent
->Common
.AmlOpcode
== AML_NAME_OP
) &&
256 (WalkState
->PassNumber
<= ACPI_IMODE_LOAD_PASS2
))
259 * Skip parsing of Buffers and Packages because we don't have
260 * enough info in the first pass to parse them correctly.
262 Op
->Named
.Data
= AmlOpStart
;
263 Op
->Named
.Length
= (UINT32
)
264 (WalkState
->ParserState
.PkgEnd
- AmlOpStart
);
268 WalkState
->ParserState
.Aml
= WalkState
->ParserState
.PkgEnd
;
269 WalkState
->ArgCount
= 0;
275 if (WalkState
->ControlState
)
277 WalkState
->ControlState
->Control
.PackageEnd
=
278 WalkState
->ParserState
.PkgEnd
;
284 /* No action for all other opcodes */
292 return_ACPI_STATUS (AE_OK
);
296 /*******************************************************************************
298 * FUNCTION: AcpiPsLinkModuleCode
300 * PARAMETERS: ParentOp - Parent parser op
301 * AmlStart - Pointer to the AML
302 * AmlLength - Length of executable AML
303 * OwnerId - OwnerId of module level code
307 * DESCRIPTION: Wrap the module-level code with a method object and link the
308 * object to the global list. Note, the mutex field of the method
309 * object is used to link multiple module-level code objects.
311 ******************************************************************************/
314 AcpiPsLinkModuleCode (
315 ACPI_PARSE_OBJECT
*ParentOp
,
318 ACPI_OWNER_ID OwnerId
)
320 ACPI_OPERAND_OBJECT
*Prev
;
321 ACPI_OPERAND_OBJECT
*Next
;
322 ACPI_OPERAND_OBJECT
*MethodObj
;
323 ACPI_NAMESPACE_NODE
*ParentNode
;
326 ACPI_FUNCTION_TRACE (PsLinkModuleCode
);
329 /* Get the tail of the list */
331 Prev
= Next
= AcpiGbl_ModuleCodeList
;
335 Next
= Next
->Method
.Mutex
;
339 * Insert the module level code into the list. Merge it if it is
340 * adjacent to the previous element.
343 ((Prev
->Method
.AmlStart
+ Prev
->Method
.AmlLength
) != AmlStart
))
345 /* Create, initialize, and link a new temporary method object */
347 MethodObj
= AcpiUtCreateInternalObject (ACPI_TYPE_METHOD
);
353 ACPI_DEBUG_PRINT ((ACPI_DB_PARSE
,
354 "Create/Link new code block: %p\n", MethodObj
));
356 if (ParentOp
->Common
.Node
)
358 ParentNode
= ParentOp
->Common
.Node
;
362 ParentNode
= AcpiGbl_RootNode
;
365 MethodObj
->Method
.AmlStart
= AmlStart
;
366 MethodObj
->Method
.AmlLength
= AmlLength
;
367 MethodObj
->Method
.OwnerId
= OwnerId
;
368 MethodObj
->Method
.InfoFlags
|= ACPI_METHOD_MODULE_LEVEL
;
371 * Save the parent node in NextObject. This is cheating, but we
372 * don't want to expand the method object.
374 MethodObj
->Method
.NextObject
=
375 ACPI_CAST_PTR (ACPI_OPERAND_OBJECT
, ParentNode
);
379 AcpiGbl_ModuleCodeList
= MethodObj
;
383 Prev
->Method
.Mutex
= MethodObj
;
388 ACPI_DEBUG_PRINT ((ACPI_DB_PARSE
,
389 "Appending to existing code block: %p\n", Prev
));
391 Prev
->Method
.AmlLength
+= AmlLength
;
397 /*******************************************************************************
399 * FUNCTION: AcpiPsParseLoop
401 * PARAMETERS: WalkState - Current state
405 * DESCRIPTION: Parse AML (pointed to by the current parser state) and return
408 ******************************************************************************/
412 ACPI_WALK_STATE
*WalkState
)
414 ACPI_STATUS Status
= AE_OK
;
415 ACPI_PARSE_OBJECT
*Op
= NULL
; /* current op */
416 ACPI_PARSE_STATE
*ParserState
;
417 UINT8
*AmlOpStart
= NULL
;
420 ACPI_FUNCTION_TRACE_PTR (PsParseLoop
, WalkState
);
423 if (WalkState
->DescendingCallback
== NULL
)
425 return_ACPI_STATUS (AE_BAD_PARAMETER
);
428 ParserState
= &WalkState
->ParserState
;
429 WalkState
->ArgTypes
= 0;
431 #if (!defined (ACPI_NO_METHOD_EXECUTION) && !defined (ACPI_CONSTANT_EVAL_ONLY))
433 if (WalkState
->WalkType
& ACPI_WALK_METHOD_RESTART
)
435 /* We are restarting a preempted control method */
437 if (AcpiPsHasCompletedScope (ParserState
))
440 * We must check if a predicate to an IF or WHILE statement
443 if ((ParserState
->Scope
->ParseScope
.Op
) &&
444 ((ParserState
->Scope
->ParseScope
.Op
->Common
.AmlOpcode
== AML_IF_OP
) ||
445 (ParserState
->Scope
->ParseScope
.Op
->Common
.AmlOpcode
== AML_WHILE_OP
)) &&
446 (WalkState
->ControlState
) &&
447 (WalkState
->ControlState
->Common
.State
==
448 ACPI_CONTROL_PREDICATE_EXECUTING
))
451 * A predicate was just completed, get the value of the
452 * predicate and branch based on that value
454 WalkState
->Op
= NULL
;
455 Status
= AcpiDsGetPredicateValue (WalkState
, ACPI_TO_POINTER (TRUE
));
456 if (ACPI_FAILURE (Status
) &&
457 ((Status
& AE_CODE_MASK
) != AE_CODE_CONTROL
))
459 if (Status
== AE_AML_NO_RETURN_VALUE
)
461 ACPI_EXCEPTION ((AE_INFO
, Status
,
462 "Invoked method did not return a value"));
465 ACPI_EXCEPTION ((AE_INFO
, Status
, "GetPredicate Failed"));
466 return_ACPI_STATUS (Status
);
469 Status
= AcpiPsNextParseState (WalkState
, Op
, Status
);
472 AcpiPsPopScope (ParserState
, &Op
,
473 &WalkState
->ArgTypes
, &WalkState
->ArgCount
);
474 ACPI_DEBUG_PRINT ((ACPI_DB_PARSE
, "Popped scope, Op=%p\n", Op
));
476 else if (WalkState
->PrevOp
)
478 /* We were in the middle of an op */
480 Op
= WalkState
->PrevOp
;
481 WalkState
->ArgTypes
= WalkState
->PrevArgTypes
;
486 /* Iterative parsing loop, while there is more AML to process: */
488 while ((ParserState
->Aml
< ParserState
->AmlEnd
) || (Op
))
490 AmlOpStart
= ParserState
->Aml
;
493 Status
= AcpiPsCreateOp (WalkState
, AmlOpStart
, &Op
);
494 if (ACPI_FAILURE (Status
))
496 if (Status
== AE_CTRL_PARSE_CONTINUE
)
501 if (Status
== AE_CTRL_PARSE_PENDING
)
506 if (Status
== AE_CTRL_TERMINATE
)
508 return_ACPI_STATUS (Status
);
511 Status
= AcpiPsCompleteOp (WalkState
, &Op
, Status
);
512 if (ACPI_FAILURE (Status
))
514 return_ACPI_STATUS (Status
);
520 AcpiExStartTraceOpcode (Op
, WalkState
);
525 * Start ArgCount at zero because we don't know if there are
528 WalkState
->ArgCount
= 0;
530 /* Are there any arguments that must be processed? */
532 if (WalkState
->ArgTypes
)
536 Status
= AcpiPsGetArguments (WalkState
, AmlOpStart
, Op
);
537 if (ACPI_FAILURE (Status
))
539 Status
= AcpiPsCompleteOp (WalkState
, &Op
, Status
);
540 if (ACPI_FAILURE (Status
))
542 return_ACPI_STATUS (Status
);
549 /* Check for arguments that need to be processed */
551 if (WalkState
->ArgCount
)
554 * There are arguments (complex ones), push Op and
555 * prepare for argument
557 Status
= AcpiPsPushScope (ParserState
, Op
,
558 WalkState
->ArgTypes
, WalkState
->ArgCount
);
559 if (ACPI_FAILURE (Status
))
561 Status
= AcpiPsCompleteOp (WalkState
, &Op
, Status
);
562 if (ACPI_FAILURE (Status
))
564 return_ACPI_STATUS (Status
);
575 * All arguments have been processed -- Op is complete,
578 WalkState
->OpInfo
= AcpiPsGetOpcodeInfo (Op
->Common
.AmlOpcode
);
579 if (WalkState
->OpInfo
->Flags
& AML_NAMED
)
581 if (Op
->Common
.AmlOpcode
== AML_REGION_OP
||
582 Op
->Common
.AmlOpcode
== AML_DATA_REGION_OP
)
585 * Skip parsing of control method or opregion body,
586 * because we don't have enough info in the first pass
587 * to parse them correctly.
589 * Completed parsing an OpRegion declaration, we now
592 Op
->Named
.Length
= (UINT32
) (ParserState
->Aml
- Op
->Named
.Data
);
596 if (WalkState
->OpInfo
->Flags
& AML_CREATE
)
599 * Backup to beginning of CreateXXXfield declaration (1 for
602 * BodyLength is unknown until we parse the body
604 Op
->Named
.Length
= (UINT32
) (ParserState
->Aml
- Op
->Named
.Data
);
607 if (Op
->Common
.AmlOpcode
== AML_BANK_FIELD_OP
)
610 * Backup to beginning of BankField declaration
612 * BodyLength is unknown until we parse the body
614 Op
->Named
.Length
= (UINT32
) (ParserState
->Aml
- Op
->Named
.Data
);
617 /* This op complete, notify the dispatcher */
619 if (WalkState
->AscendingCallback
!= NULL
)
622 WalkState
->Opcode
= Op
->Common
.AmlOpcode
;
624 Status
= WalkState
->AscendingCallback (WalkState
);
625 Status
= AcpiPsNextParseState (WalkState
, Op
, Status
);
626 if (Status
== AE_CTRL_PENDING
)
632 Status
= AcpiPsCompleteOp (WalkState
, &Op
, Status
);
633 if (ACPI_FAILURE (Status
))
635 return_ACPI_STATUS (Status
);
638 } /* while ParserState->Aml */
640 Status
= AcpiPsCompleteFinalOp (WalkState
, Op
, Status
);
641 return_ACPI_STATUS (Status
);