1 /******************************************************************************
3 * Module Name: psloop - Main AML parse loop
5 *****************************************************************************/
8 * Copyright (C) 2000 - 2013, 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.
46 * Parse the AML and build an operation tree as most interpreters, (such as
47 * Perl) do. Parsing is done by hand rather than with a YACC generated parser
48 * to tightly constrain stack and dynamic memory usage. Parsing is kept
49 * flexible and the code fairly compact by parsing based on a list of AML
50 * 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 switch (Op
->Common
.AmlOpcode
)
109 case AML_BYTE_OP
: /* AML_BYTEDATA_ARG */
110 case AML_WORD_OP
: /* AML_WORDDATA_ARG */
111 case AML_DWORD_OP
: /* AML_DWORDATA_ARG */
112 case AML_QWORD_OP
: /* AML_QWORDATA_ARG */
113 case AML_STRING_OP
: /* AML_ASCIICHARLIST_ARG */
115 /* Fill in constant or string argument directly */
117 AcpiPsGetNextSimpleArg (&(WalkState
->ParserState
),
118 GET_CURRENT_ARG_TYPE (WalkState
->ArgTypes
), Op
);
121 case AML_INT_NAMEPATH_OP
: /* AML_NAMESTRING_ARG */
123 Status
= AcpiPsGetNextNamepath (WalkState
, &(WalkState
->ParserState
), Op
, 1);
124 if (ACPI_FAILURE (Status
))
126 return_ACPI_STATUS (Status
);
129 WalkState
->ArgTypes
= 0;
134 * Op is not a constant or string, append each argument to the Op
136 while (GET_CURRENT_ARG_TYPE (WalkState
->ArgTypes
) && !WalkState
->ArgCount
)
138 WalkState
->AmlOffset
= (UINT32
) ACPI_PTR_DIFF (WalkState
->ParserState
.Aml
,
139 WalkState
->ParserState
.AmlStart
);
141 Status
= AcpiPsGetNextArg (WalkState
, &(WalkState
->ParserState
),
142 GET_CURRENT_ARG_TYPE (WalkState
->ArgTypes
), &Arg
);
143 if (ACPI_FAILURE (Status
))
145 return_ACPI_STATUS (Status
);
150 Arg
->Common
.AmlOffset
= WalkState
->AmlOffset
;
151 AcpiPsAppendArg (Op
, Arg
);
154 INCREMENT_ARG_LIST (WalkState
->ArgTypes
);
159 * Handle executable code at "module-level". This refers to
160 * executable opcodes that appear outside of any control method.
162 if ((WalkState
->PassNumber
<= ACPI_IMODE_LOAD_PASS2
) &&
163 ((WalkState
->ParseFlags
& ACPI_PARSE_DISASSEMBLE
) == 0))
166 * We want to skip If/Else/While constructs during Pass1 because we
167 * want to actually conditionally execute the code during Pass2.
169 * Except for disassembly, where we always want to walk the
170 * If/Else/While packages
172 switch (Op
->Common
.AmlOpcode
)
178 * Currently supported module-level opcodes are:
179 * IF/ELSE/WHILE. These appear to be the most common,
180 * and easiest to support since they open an AML
183 if (WalkState
->PassNumber
== ACPI_IMODE_LOAD_PASS1
)
185 AcpiPsLinkModuleCode (Op
->Common
.Parent
, AmlOpStart
,
186 (UINT32
) (WalkState
->ParserState
.PkgEnd
- AmlOpStart
),
190 ACPI_DEBUG_PRINT ((ACPI_DB_PARSE
,
191 "Pass1: Skipping an If/Else/While body\n"));
193 /* Skip body of if/else/while in pass 1 */
195 WalkState
->ParserState
.Aml
= WalkState
->ParserState
.PkgEnd
;
196 WalkState
->ArgCount
= 0;
201 * Check for an unsupported executable opcode at module
202 * level. We must be in PASS1, the parent must be a SCOPE,
203 * The opcode class must be EXECUTE, and the opcode must
204 * not be an argument to another opcode.
206 if ((WalkState
->PassNumber
== ACPI_IMODE_LOAD_PASS1
) &&
207 (Op
->Common
.Parent
->Common
.AmlOpcode
== AML_SCOPE_OP
))
209 OpInfo
= AcpiPsGetOpcodeInfo (Op
->Common
.AmlOpcode
);
210 if ((OpInfo
->Class
== AML_CLASS_EXECUTE
) &&
213 ACPI_WARNING ((AE_INFO
,
214 "Unsupported module-level executable opcode "
215 "0x%.2X at table offset 0x%.4X",
216 Op
->Common
.AmlOpcode
,
217 (UINT32
) (ACPI_PTR_DIFF (AmlOpStart
,
218 WalkState
->ParserState
.AmlStart
) +
219 sizeof (ACPI_TABLE_HEADER
))));
226 /* Special processing for certain opcodes */
228 switch (Op
->Common
.AmlOpcode
)
232 * Skip parsing of control method because we don't have enough
233 * info in the first pass to parse it correctly.
235 * Save the length and address of the body
237 Op
->Named
.Data
= WalkState
->ParserState
.Aml
;
238 Op
->Named
.Length
= (UINT32
)
239 (WalkState
->ParserState
.PkgEnd
- WalkState
->ParserState
.Aml
);
241 /* Skip body of method */
243 WalkState
->ParserState
.Aml
= WalkState
->ParserState
.PkgEnd
;
244 WalkState
->ArgCount
= 0;
249 case AML_VAR_PACKAGE_OP
:
251 if ((Op
->Common
.Parent
) &&
252 (Op
->Common
.Parent
->Common
.AmlOpcode
== AML_NAME_OP
) &&
253 (WalkState
->PassNumber
<= ACPI_IMODE_LOAD_PASS2
))
256 * Skip parsing of Buffers and Packages because we don't have
257 * enough info in the first pass to parse them correctly.
259 Op
->Named
.Data
= AmlOpStart
;
260 Op
->Named
.Length
= (UINT32
)
261 (WalkState
->ParserState
.PkgEnd
- AmlOpStart
);
265 WalkState
->ParserState
.Aml
= WalkState
->ParserState
.PkgEnd
;
266 WalkState
->ArgCount
= 0;
272 if (WalkState
->ControlState
)
274 WalkState
->ControlState
->Control
.PackageEnd
=
275 WalkState
->ParserState
.PkgEnd
;
281 /* No action for all other opcodes */
289 return_ACPI_STATUS (AE_OK
);
293 /*******************************************************************************
295 * FUNCTION: AcpiPsLinkModuleCode
297 * PARAMETERS: ParentOp - Parent parser op
298 * AmlStart - Pointer to the AML
299 * AmlLength - Length of executable AML
300 * OwnerId - OwnerId of module level code
304 * DESCRIPTION: Wrap the module-level code with a method object and link the
305 * object to the global list. Note, the mutex field of the method
306 * object is used to link multiple module-level code objects.
308 ******************************************************************************/
311 AcpiPsLinkModuleCode (
312 ACPI_PARSE_OBJECT
*ParentOp
,
315 ACPI_OWNER_ID OwnerId
)
317 ACPI_OPERAND_OBJECT
*Prev
;
318 ACPI_OPERAND_OBJECT
*Next
;
319 ACPI_OPERAND_OBJECT
*MethodObj
;
320 ACPI_NAMESPACE_NODE
*ParentNode
;
323 /* Get the tail of the list */
325 Prev
= Next
= AcpiGbl_ModuleCodeList
;
329 Next
= Next
->Method
.Mutex
;
333 * Insert the module level code into the list. Merge it if it is
334 * adjacent to the previous element.
337 ((Prev
->Method
.AmlStart
+ Prev
->Method
.AmlLength
) != AmlStart
))
339 /* Create, initialize, and link a new temporary method object */
341 MethodObj
= AcpiUtCreateInternalObject (ACPI_TYPE_METHOD
);
347 if (ParentOp
->Common
.Node
)
349 ParentNode
= ParentOp
->Common
.Node
;
353 ParentNode
= AcpiGbl_RootNode
;
356 MethodObj
->Method
.AmlStart
= AmlStart
;
357 MethodObj
->Method
.AmlLength
= AmlLength
;
358 MethodObj
->Method
.OwnerId
= OwnerId
;
359 MethodObj
->Method
.InfoFlags
|= ACPI_METHOD_MODULE_LEVEL
;
362 * Save the parent node in NextObject. This is cheating, but we
363 * don't want to expand the method object.
365 MethodObj
->Method
.NextObject
=
366 ACPI_CAST_PTR (ACPI_OPERAND_OBJECT
, ParentNode
);
370 AcpiGbl_ModuleCodeList
= MethodObj
;
374 Prev
->Method
.Mutex
= MethodObj
;
379 Prev
->Method
.AmlLength
+= AmlLength
;
383 /*******************************************************************************
385 * FUNCTION: AcpiPsParseLoop
387 * PARAMETERS: WalkState - Current state
391 * DESCRIPTION: Parse AML (pointed to by the current parser state) and return
394 ******************************************************************************/
398 ACPI_WALK_STATE
*WalkState
)
400 ACPI_STATUS Status
= AE_OK
;
401 ACPI_PARSE_OBJECT
*Op
= NULL
; /* current op */
402 ACPI_PARSE_STATE
*ParserState
;
403 UINT8
*AmlOpStart
= NULL
;
406 ACPI_FUNCTION_TRACE_PTR (PsParseLoop
, WalkState
);
409 if (WalkState
->DescendingCallback
== NULL
)
411 return_ACPI_STATUS (AE_BAD_PARAMETER
);
414 ParserState
= &WalkState
->ParserState
;
415 WalkState
->ArgTypes
= 0;
417 #if (!defined (ACPI_NO_METHOD_EXECUTION) && !defined (ACPI_CONSTANT_EVAL_ONLY))
419 if (WalkState
->WalkType
& ACPI_WALK_METHOD_RESTART
)
421 /* We are restarting a preempted control method */
423 if (AcpiPsHasCompletedScope (ParserState
))
426 * We must check if a predicate to an IF or WHILE statement
429 if ((ParserState
->Scope
->ParseScope
.Op
) &&
430 ((ParserState
->Scope
->ParseScope
.Op
->Common
.AmlOpcode
== AML_IF_OP
) ||
431 (ParserState
->Scope
->ParseScope
.Op
->Common
.AmlOpcode
== AML_WHILE_OP
)) &&
432 (WalkState
->ControlState
) &&
433 (WalkState
->ControlState
->Common
.State
==
434 ACPI_CONTROL_PREDICATE_EXECUTING
))
437 * A predicate was just completed, get the value of the
438 * predicate and branch based on that value
440 WalkState
->Op
= NULL
;
441 Status
= AcpiDsGetPredicateValue (WalkState
, ACPI_TO_POINTER (TRUE
));
442 if (ACPI_FAILURE (Status
) &&
443 ((Status
& AE_CODE_MASK
) != AE_CODE_CONTROL
))
445 if (Status
== AE_AML_NO_RETURN_VALUE
)
447 ACPI_EXCEPTION ((AE_INFO
, Status
,
448 "Invoked method did not return a value"));
451 ACPI_EXCEPTION ((AE_INFO
, Status
, "GetPredicate Failed"));
452 return_ACPI_STATUS (Status
);
455 Status
= AcpiPsNextParseState (WalkState
, Op
, Status
);
458 AcpiPsPopScope (ParserState
, &Op
,
459 &WalkState
->ArgTypes
, &WalkState
->ArgCount
);
460 ACPI_DEBUG_PRINT ((ACPI_DB_PARSE
, "Popped scope, Op=%p\n", Op
));
462 else if (WalkState
->PrevOp
)
464 /* We were in the middle of an op */
466 Op
= WalkState
->PrevOp
;
467 WalkState
->ArgTypes
= WalkState
->PrevArgTypes
;
472 /* Iterative parsing loop, while there is more AML to process: */
474 while ((ParserState
->Aml
< ParserState
->AmlEnd
) || (Op
))
476 AmlOpStart
= ParserState
->Aml
;
479 Status
= AcpiPsCreateOp (WalkState
, AmlOpStart
, &Op
);
480 if (ACPI_FAILURE (Status
))
482 if (Status
== AE_CTRL_PARSE_CONTINUE
)
487 if (Status
== AE_CTRL_PARSE_PENDING
)
492 Status
= AcpiPsCompleteOp (WalkState
, &Op
, Status
);
493 if (ACPI_FAILURE (Status
))
495 return_ACPI_STATUS (Status
);
501 Op
->Common
.AmlOffset
= WalkState
->AmlOffset
;
503 if (WalkState
->OpInfo
)
505 ACPI_DEBUG_PRINT ((ACPI_DB_PARSE
,
506 "Opcode %4.4X [%s] Op %p Aml %p AmlOffset %5.5X\n",
507 (UINT32
) Op
->Common
.AmlOpcode
, WalkState
->OpInfo
->Name
,
508 Op
, ParserState
->Aml
, Op
->Common
.AmlOffset
));
514 * Start ArgCount at zero because we don't know if there are
517 WalkState
->ArgCount
= 0;
519 /* Are there any arguments that must be processed? */
521 if (WalkState
->ArgTypes
)
525 Status
= AcpiPsGetArguments (WalkState
, AmlOpStart
, Op
);
526 if (ACPI_FAILURE (Status
))
528 Status
= AcpiPsCompleteOp (WalkState
, &Op
, Status
);
529 if (ACPI_FAILURE (Status
))
531 return_ACPI_STATUS (Status
);
538 /* Check for arguments that need to be processed */
540 if (WalkState
->ArgCount
)
543 * There are arguments (complex ones), push Op and
544 * prepare for argument
546 Status
= AcpiPsPushScope (ParserState
, Op
,
547 WalkState
->ArgTypes
, WalkState
->ArgCount
);
548 if (ACPI_FAILURE (Status
))
550 Status
= AcpiPsCompleteOp (WalkState
, &Op
, Status
);
551 if (ACPI_FAILURE (Status
))
553 return_ACPI_STATUS (Status
);
564 * All arguments have been processed -- Op is complete,
567 WalkState
->OpInfo
= AcpiPsGetOpcodeInfo (Op
->Common
.AmlOpcode
);
568 if (WalkState
->OpInfo
->Flags
& AML_NAMED
)
570 if (Op
->Common
.AmlOpcode
== AML_REGION_OP
||
571 Op
->Common
.AmlOpcode
== AML_DATA_REGION_OP
)
574 * Skip parsing of control method or opregion body,
575 * because we don't have enough info in the first pass
576 * to parse them correctly.
578 * Completed parsing an OpRegion declaration, we now
581 Op
->Named
.Length
= (UINT32
) (ParserState
->Aml
- Op
->Named
.Data
);
585 if (WalkState
->OpInfo
->Flags
& AML_CREATE
)
588 * Backup to beginning of CreateXXXfield declaration (1 for
591 * BodyLength is unknown until we parse the body
593 Op
->Named
.Length
= (UINT32
) (ParserState
->Aml
- Op
->Named
.Data
);
596 if (Op
->Common
.AmlOpcode
== AML_BANK_FIELD_OP
)
599 * Backup to beginning of BankField declaration
601 * BodyLength is unknown until we parse the body
603 Op
->Named
.Length
= (UINT32
) (ParserState
->Aml
- Op
->Named
.Data
);
606 /* This op complete, notify the dispatcher */
608 if (WalkState
->AscendingCallback
!= NULL
)
611 WalkState
->Opcode
= Op
->Common
.AmlOpcode
;
613 Status
= WalkState
->AscendingCallback (WalkState
);
614 Status
= AcpiPsNextParseState (WalkState
, Op
, Status
);
615 if (Status
== AE_CTRL_PENDING
)
621 Status
= AcpiPsCompleteOp (WalkState
, &Op
, Status
);
622 if (ACPI_FAILURE (Status
))
624 return_ACPI_STATUS (Status
);
627 } /* while ParserState->Aml */
629 Status
= AcpiPsCompleteFinalOp (WalkState
, Op
, Status
);
630 return_ACPI_STATUS (Status
);