Indentation fix, cleanup.
[AROS.git] / arch / all-pc / acpica / source / components / parser / psloop.c
blob0afcb4ca0d3ee3b9ad32d05d7c77d291fef00627
1 /******************************************************************************
3 * Module Name: psloop - Main AML parse loop
5 *****************************************************************************/
7 /*
8 * Copyright (C) 2000 - 2013, Intel Corp.
9 * All rights reserved.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
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.
30 * NO WARRANTY
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[].
53 #include "acpi.h"
54 #include "accommon.h"
55 #include "acparser.h"
56 #include "acdispat.h"
57 #include "amlcode.h"
59 #define _COMPONENT ACPI_PARSER
60 ACPI_MODULE_NAME ("psloop")
63 /* Local prototypes */
65 static ACPI_STATUS
66 AcpiPsGetArguments (
67 ACPI_WALK_STATE *WalkState,
68 UINT8 *AmlOpStart,
69 ACPI_PARSE_OBJECT *Op);
71 static void
72 AcpiPsLinkModuleCode (
73 ACPI_PARSE_OBJECT *ParentOp,
74 UINT8 *AmlStart,
75 UINT32 AmlLength,
76 ACPI_OWNER_ID OwnerId);
79 /*******************************************************************************
81 * FUNCTION: AcpiPsGetArguments
83 * PARAMETERS: WalkState - Current state
84 * AmlOpStart - Op start in AML
85 * Op - Current Op
87 * RETURN: Status
89 * DESCRIPTION: Get arguments for passed Op.
91 ******************************************************************************/
93 static ACPI_STATUS
94 AcpiPsGetArguments (
95 ACPI_WALK_STATE *WalkState,
96 UINT8 *AmlOpStart,
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);
119 break;
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;
130 break;
132 default:
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);
148 if (Arg)
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)
174 case AML_IF_OP:
175 case AML_ELSE_OP:
176 case AML_WHILE_OP:
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
181 * package.
183 if (WalkState->PassNumber == ACPI_IMODE_LOAD_PASS1)
185 AcpiPsLinkModuleCode (Op->Common.Parent, AmlOpStart,
186 (UINT32) (WalkState->ParserState.PkgEnd - AmlOpStart),
187 WalkState->OwnerId);
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;
197 break;
199 default:
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) &&
211 (!Arg))
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))));
222 break;
226 /* Special processing for certain opcodes */
228 switch (Op->Common.AmlOpcode)
230 case AML_METHOD_OP:
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;
245 break;
247 case AML_BUFFER_OP:
248 case AML_PACKAGE_OP:
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);
263 /* Skip body */
265 WalkState->ParserState.Aml = WalkState->ParserState.PkgEnd;
266 WalkState->ArgCount = 0;
268 break;
270 case AML_WHILE_OP:
272 if (WalkState->ControlState)
274 WalkState->ControlState->Control.PackageEnd =
275 WalkState->ParserState.PkgEnd;
277 break;
279 default:
281 /* No action for all other opcodes */
283 break;
286 break;
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
302 * RETURN: None.
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 ******************************************************************************/
310 static void
311 AcpiPsLinkModuleCode (
312 ACPI_PARSE_OBJECT *ParentOp,
313 UINT8 *AmlStart,
314 UINT32 AmlLength,
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;
326 while (Next)
328 Prev = Next;
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.
336 if (!Prev ||
337 ((Prev->Method.AmlStart + Prev->Method.AmlLength) != AmlStart))
339 /* Create, initialize, and link a new temporary method object */
341 MethodObj = AcpiUtCreateInternalObject (ACPI_TYPE_METHOD);
342 if (!MethodObj)
344 return;
347 if (ParentOp->Common.Node)
349 ParentNode = ParentOp->Common.Node;
351 else
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);
368 if (!Prev)
370 AcpiGbl_ModuleCodeList = MethodObj;
372 else
374 Prev->Method.Mutex = MethodObj;
377 else
379 Prev->Method.AmlLength += AmlLength;
383 /*******************************************************************************
385 * FUNCTION: AcpiPsParseLoop
387 * PARAMETERS: WalkState - Current state
389 * RETURN: Status
391 * DESCRIPTION: Parse AML (pointed to by the current parser state) and return
392 * a tree of ops.
394 ******************************************************************************/
396 ACPI_STATUS
397 AcpiPsParseLoop (
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
427 * was just completed
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;
470 #endif
472 /* Iterative parsing loop, while there is more AML to process: */
474 while ((ParserState->Aml < ParserState->AmlEnd) || (Op))
476 AmlOpStart = ParserState->Aml;
477 if (!Op)
479 Status = AcpiPsCreateOp (WalkState, AmlOpStart, &Op);
480 if (ACPI_FAILURE (Status))
482 if (Status == AE_CTRL_PARSE_CONTINUE)
484 continue;
487 if (Status == AE_CTRL_PARSE_PENDING)
489 Status = AE_OK;
492 Status = AcpiPsCompleteOp (WalkState, &Op, Status);
493 if (ACPI_FAILURE (Status))
495 return_ACPI_STATUS (Status);
498 continue;
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
515 * any args yet
517 WalkState->ArgCount = 0;
519 /* Are there any arguments that must be processed? */
521 if (WalkState->ArgTypes)
523 /* Get arguments */
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);
534 continue;
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);
556 continue;
559 Op = NULL;
560 continue;
564 * All arguments have been processed -- Op is complete,
565 * prepare for next
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
579 * know the length.
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
589 * Opcode)
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)
610 WalkState->Op = Op;
611 WalkState->Opcode = Op->Common.AmlOpcode;
613 Status = WalkState->AscendingCallback (WalkState);
614 Status = AcpiPsNextParseState (WalkState, Op, Status);
615 if (Status == AE_CTRL_PENDING)
617 Status = AE_OK;
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);