167754Smsmith/****************************************************************************** 267754Smsmith * 367754Smsmith * Module Name: psparse - Parser top level AML parse routines 467754Smsmith * 567754Smsmith *****************************************************************************/ 667754Smsmith 7217365Sjkim/* 8306536Sjkim * Copyright (C) 2000 - 2016, Intel Corp. 970243Smsmith * All rights reserved. 1067754Smsmith * 11217365Sjkim * Redistribution and use in source and binary forms, with or without 12217365Sjkim * modification, are permitted provided that the following conditions 13217365Sjkim * are met: 14217365Sjkim * 1. Redistributions of source code must retain the above copyright 15217365Sjkim * notice, this list of conditions, and the following disclaimer, 16217365Sjkim * without modification. 17217365Sjkim * 2. Redistributions in binary form must reproduce at minimum a disclaimer 18217365Sjkim * substantially similar to the "NO WARRANTY" disclaimer below 19217365Sjkim * ("Disclaimer") and any redistribution must be conditioned upon 20217365Sjkim * including a substantially similar Disclaimer requirement for further 21217365Sjkim * binary redistribution. 22217365Sjkim * 3. Neither the names of the above-listed copyright holders nor the names 23217365Sjkim * of any contributors may be used to endorse or promote products derived 24217365Sjkim * from this software without specific prior written permission. 2567754Smsmith * 26217365Sjkim * Alternatively, this software may be distributed under the terms of the 27217365Sjkim * GNU General Public License ("GPL") version 2 as published by the Free 28217365Sjkim * Software Foundation. 2967754Smsmith * 30217365Sjkim * NO WARRANTY 31217365Sjkim * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 32217365Sjkim * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 33217365Sjkim * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR 34217365Sjkim * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 35217365Sjkim * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 36217365Sjkim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 37217365Sjkim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 38217365Sjkim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 39217365Sjkim * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 40217365Sjkim * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 41217365Sjkim * POSSIBILITY OF SUCH DAMAGES. 42217365Sjkim */ 4367754Smsmith 4467754Smsmith/* 4567754Smsmith * Parse the AML and build an operation tree as most interpreters, 46241973Sjkim * like Perl, do. Parsing is done by hand rather than with a YACC 4767754Smsmith * generated parser to tightly constrain stack and dynamic memory 48241973Sjkim * usage. At the same time, parsing is kept flexible and the code 4967754Smsmith * fairly compact by parsing based on a list of AML opcode 5069450Smsmith * templates in AmlOpInfo[] 5167754Smsmith */ 5267754Smsmith 53193341Sjkim#include <contrib/dev/acpica/include/acpi.h> 54193341Sjkim#include <contrib/dev/acpica/include/accommon.h> 55193341Sjkim#include <contrib/dev/acpica/include/acparser.h> 56193341Sjkim#include <contrib/dev/acpica/include/acdispat.h> 57193341Sjkim#include <contrib/dev/acpica/include/amlcode.h> 58193341Sjkim#include <contrib/dev/acpica/include/acinterp.h> 5967754Smsmith 6077424Smsmith#define _COMPONENT ACPI_PARSER 6191116Smsmith ACPI_MODULE_NAME ("psparse") 6267754Smsmith 6367754Smsmith 6467754Smsmith/******************************************************************************* 6567754Smsmith * 6683174Smsmith * FUNCTION: AcpiPsGetOpcodeSize 6767754Smsmith * 6883174Smsmith * PARAMETERS: Opcode - An AML opcode 6967754Smsmith * 7083174Smsmith * RETURN: Size of the opcode, in bytes (1 or 2) 7167754Smsmith * 7283174Smsmith * DESCRIPTION: Get the size of the current opcode. 7367754Smsmith * 7467754Smsmith ******************************************************************************/ 7567754Smsmith 7687031SmsmithUINT32 7767754SmsmithAcpiPsGetOpcodeSize ( 7867754Smsmith UINT32 Opcode) 7967754Smsmith{ 8067754Smsmith 8167754Smsmith /* Extended (2-byte) opcode if > 255 */ 8267754Smsmith 8367754Smsmith if (Opcode > 0x00FF) 8467754Smsmith { 8567754Smsmith return (2); 8667754Smsmith } 8767754Smsmith 8867754Smsmith /* Otherwise, just a single byte opcode */ 8967754Smsmith 9067754Smsmith return (1); 9167754Smsmith} 9267754Smsmith 9367754Smsmith 9467754Smsmith/******************************************************************************* 9567754Smsmith * 9667754Smsmith * FUNCTION: AcpiPsPeekOpcode 9767754Smsmith * 9867754Smsmith * PARAMETERS: ParserState - A parser state object 9967754Smsmith * 100151937Sjkim * RETURN: Next AML opcode 10167754Smsmith * 10267754Smsmith * DESCRIPTION: Get next AML opcode (without incrementing AML pointer) 10367754Smsmith * 10467754Smsmith ******************************************************************************/ 10567754Smsmith 10667754SmsmithUINT16 10767754SmsmithAcpiPsPeekOpcode ( 10867754Smsmith ACPI_PARSE_STATE *ParserState) 10967754Smsmith{ 11067754Smsmith UINT8 *Aml; 11167754Smsmith UINT16 Opcode; 11267754Smsmith 11367754Smsmith 11467754Smsmith Aml = ParserState->Aml; 11591116Smsmith Opcode = (UINT16) ACPI_GET8 (Aml); 11667754Smsmith 117151937Sjkim if (Opcode == AML_EXTENDED_OP_PREFIX) 11867754Smsmith { 119151937Sjkim /* Extended opcode, get the second opcode byte */ 12067754Smsmith 12187031Smsmith Aml++; 12291116Smsmith Opcode = (UINT16) ((Opcode << 8) | ACPI_GET8 (Aml)); 12367754Smsmith } 12467754Smsmith 12567754Smsmith return (Opcode); 12667754Smsmith} 12767754Smsmith 12867754Smsmith 12967754Smsmith/******************************************************************************* 13067754Smsmith * 13167754Smsmith * FUNCTION: AcpiPsCompleteThisOp 13267754Smsmith * 13367754Smsmith * PARAMETERS: WalkState - Current State 13467754Smsmith * Op - Op to complete 13567754Smsmith * 136151937Sjkim * RETURN: Status 13767754Smsmith * 13867754Smsmith * DESCRIPTION: Perform any cleanup at the completion of an Op. 13967754Smsmith * 14067754Smsmith ******************************************************************************/ 14167754Smsmith 142151937SjkimACPI_STATUS 14367754SmsmithAcpiPsCompleteThisOp ( 14467754Smsmith ACPI_WALK_STATE *WalkState, 14567754Smsmith ACPI_PARSE_OBJECT *Op) 14667754Smsmith{ 14767754Smsmith ACPI_PARSE_OBJECT *Prev; 14867754Smsmith ACPI_PARSE_OBJECT *Next; 14983174Smsmith const ACPI_OPCODE_INFO *ParentInfo; 15067754Smsmith ACPI_PARSE_OBJECT *ReplacementOp = NULL; 151193267Sjkim ACPI_STATUS Status = AE_OK; 15267754Smsmith 15367754Smsmith 154167802Sjkim ACPI_FUNCTION_TRACE_PTR (PsCompleteThisOp, Op); 15567754Smsmith 15667754Smsmith 15791116Smsmith /* Check for null Op, can happen if AML code is corrupt */ 15891116Smsmith 15991116Smsmith if (!Op) 16091116Smsmith { 161151937Sjkim return_ACPI_STATUS (AE_OK); /* OK for now */ 16291116Smsmith } 16391116Smsmith 164306536Sjkim AcpiExStopTraceOpcode (Op, WalkState); 165306536Sjkim 16667754Smsmith /* Delete this op and the subtree below it if asked to */ 16767754Smsmith 168138287Smarks if (((WalkState->ParseFlags & ACPI_PARSE_TREE_MASK) != ACPI_PARSE_DELETE_TREE) || 169138287Smarks (WalkState->OpInfo->Class == AML_CLASS_ARGUMENT)) 17067754Smsmith { 171151937Sjkim return_ACPI_STATUS (AE_OK); 172138287Smarks } 17367754Smsmith 174138287Smarks /* Make sure that we only delete this subtree */ 175138287Smarks 176138287Smarks if (Op->Common.Parent) 177138287Smarks { 178151937Sjkim Prev = Op->Common.Parent->Common.Value.Arg; 179151937Sjkim if (!Prev) 180151937Sjkim { 181151937Sjkim /* Nothing more to do */ 182151937Sjkim 183151937Sjkim goto Cleanup; 184151937Sjkim } 185151937Sjkim 186138287Smarks /* 187138287Smarks * Check if we need to replace the operator and its subtree 188138287Smarks * with a return value op (placeholder op) 189138287Smarks */ 190151937Sjkim ParentInfo = AcpiPsGetOpcodeInfo (Op->Common.Parent->Common.AmlOpcode); 191138287Smarks 192138287Smarks switch (ParentInfo->Class) 19367754Smsmith { 194138287Smarks case AML_CLASS_CONTROL: 195250838Sjkim 196138287Smarks break; 197138287Smarks 198138287Smarks case AML_CLASS_CREATE: 19967754Smsmith /* 200241973Sjkim * These opcodes contain TermArg operands. The current 201138287Smarks * op must be replaced by a placeholder return op 20267754Smsmith */ 203306536Sjkim ReplacementOp = AcpiPsAllocOp ( 204306536Sjkim AML_INT_RETURN_VALUE_OP, Op->Common.Aml); 205138287Smarks if (!ReplacementOp) 20667754Smsmith { 207193267Sjkim Status = AE_NO_MEMORY; 208138287Smarks } 209138287Smarks break; 21069746Smsmith 211138287Smarks case AML_CLASS_NAMED_OBJECT: 212138287Smarks /* 213241973Sjkim * These opcodes contain TermArg operands. The current 214138287Smarks * op must be replaced by a placeholder return op 215138287Smarks */ 216138287Smarks if ((Op->Common.Parent->Common.AmlOpcode == AML_REGION_OP) || 217138287Smarks (Op->Common.Parent->Common.AmlOpcode == AML_DATA_REGION_OP) || 218138287Smarks (Op->Common.Parent->Common.AmlOpcode == AML_BUFFER_OP) || 219138287Smarks (Op->Common.Parent->Common.AmlOpcode == AML_PACKAGE_OP) || 220193267Sjkim (Op->Common.Parent->Common.AmlOpcode == AML_BANK_FIELD_OP) || 221138287Smarks (Op->Common.Parent->Common.AmlOpcode == AML_VAR_PACKAGE_OP)) 222138287Smarks { 223306536Sjkim ReplacementOp = AcpiPsAllocOp ( 224306536Sjkim AML_INT_RETURN_VALUE_OP, Op->Common.Aml); 22587031Smsmith if (!ReplacementOp) 22687031Smsmith { 227193267Sjkim Status = AE_NO_MEMORY; 22887031Smsmith } 229138287Smarks } 230151937Sjkim else if ((Op->Common.Parent->Common.AmlOpcode == AML_NAME_OP) && 231151937Sjkim (WalkState->PassNumber <= ACPI_IMODE_LOAD_PASS2)) 232138287Smarks { 233138287Smarks if ((Op->Common.AmlOpcode == AML_BUFFER_OP) || 234138287Smarks (Op->Common.AmlOpcode == AML_PACKAGE_OP) || 235138287Smarks (Op->Common.AmlOpcode == AML_VAR_PACKAGE_OP)) 23669746Smsmith { 237306536Sjkim ReplacementOp = AcpiPsAllocOp (Op->Common.AmlOpcode, 238306536Sjkim Op->Common.Aml); 23969746Smsmith if (!ReplacementOp) 24069746Smsmith { 241193267Sjkim Status = AE_NO_MEMORY; 24269746Smsmith } 243193267Sjkim else 244193267Sjkim { 245193267Sjkim ReplacementOp->Named.Data = Op->Named.Data; 246193267Sjkim ReplacementOp->Named.Length = Op->Named.Length; 247193267Sjkim } 24869746Smsmith } 249138287Smarks } 250138287Smarks break; 25199146Siwasaki 252138287Smarks default: 253151937Sjkim 254306536Sjkim ReplacementOp = AcpiPsAllocOp ( 255306536Sjkim AML_INT_RETURN_VALUE_OP, Op->Common.Aml); 256138287Smarks if (!ReplacementOp) 257138287Smarks { 258193267Sjkim Status = AE_NO_MEMORY; 259138287Smarks } 260138287Smarks } 26199146Siwasaki 262138287Smarks /* We must unlink this op from the parent tree */ 26399146Siwasaki 264138287Smarks if (Prev == Op) 265138287Smarks { 266138287Smarks /* This op is the first in the list */ 26767754Smsmith 268138287Smarks if (ReplacementOp) 269138287Smarks { 270306536Sjkim ReplacementOp->Common.Parent = Op->Common.Parent; 271306536Sjkim ReplacementOp->Common.Value.Arg = NULL; 272306536Sjkim ReplacementOp->Common.Node = Op->Common.Node; 273138287Smarks Op->Common.Parent->Common.Value.Arg = ReplacementOp; 274306536Sjkim ReplacementOp->Common.Next = Op->Common.Next; 27567754Smsmith } 276138287Smarks else 277138287Smarks { 278138287Smarks Op->Common.Parent->Common.Value.Arg = Op->Common.Next; 279138287Smarks } 280138287Smarks } 28167754Smsmith 282138287Smarks /* Search the parent list */ 28367754Smsmith 284138287Smarks else while (Prev) 285138287Smarks { 286138287Smarks /* Traverse all siblings in the parent's argument list */ 287138287Smarks 288138287Smarks Next = Prev->Common.Next; 289138287Smarks if (Next == Op) 29067754Smsmith { 29167754Smsmith if (ReplacementOp) 29267754Smsmith { 293306536Sjkim ReplacementOp->Common.Parent = Op->Common.Parent; 294138287Smarks ReplacementOp->Common.Value.Arg = NULL; 295306536Sjkim ReplacementOp->Common.Node = Op->Common.Node; 296306536Sjkim Prev->Common.Next = ReplacementOp; 297306536Sjkim ReplacementOp->Common.Next = Op->Common.Next; 298138287Smarks Next = NULL; 29967754Smsmith } 30067754Smsmith else 30167754Smsmith { 302138287Smarks Prev->Common.Next = Op->Common.Next; 303138287Smarks Next = NULL; 30467754Smsmith } 30567754Smsmith } 306138287Smarks Prev = Next; 30767754Smsmith } 308138287Smarks } 30967754Smsmith 31067754Smsmith 311138287SmarksCleanup: 31267754Smsmith 313151937Sjkim /* Now we can actually delete the subtree rooted at Op */ 31467754Smsmith 315138287Smarks AcpiPsDeleteParseTree (Op); 316193267Sjkim return_ACPI_STATUS (Status); 31767754Smsmith} 31867754Smsmith 31967754Smsmith 32067754Smsmith/******************************************************************************* 32167754Smsmith * 32267754Smsmith * FUNCTION: AcpiPsNextParseState 32367754Smsmith * 324151937Sjkim * PARAMETERS: WalkState - Current state 325151937Sjkim * Op - Current parse op 326151937Sjkim * CallbackStatus - Status from previous operation 32767754Smsmith * 32899146Siwasaki * RETURN: Status 32967754Smsmith * 33099146Siwasaki * DESCRIPTION: Update the parser state based upon the return exception from 33199146Siwasaki * the parser callback. 33267754Smsmith * 33367754Smsmith ******************************************************************************/ 33467754Smsmith 33587031SmsmithACPI_STATUS 33667754SmsmithAcpiPsNextParseState ( 33767754Smsmith ACPI_WALK_STATE *WalkState, 33867754Smsmith ACPI_PARSE_OBJECT *Op, 33967754Smsmith ACPI_STATUS CallbackStatus) 34067754Smsmith{ 34184491Smsmith ACPI_PARSE_STATE *ParserState = &WalkState->ParserState; 34267754Smsmith ACPI_STATUS Status = AE_CTRL_PENDING; 34367754Smsmith 34467754Smsmith 345167802Sjkim ACPI_FUNCTION_TRACE_PTR (PsNextParseState, Op); 34667754Smsmith 34767754Smsmith 34867754Smsmith switch (CallbackStatus) 34967754Smsmith { 35067754Smsmith case AE_CTRL_TERMINATE: 35167754Smsmith /* 35267754Smsmith * A control method was terminated via a RETURN statement. 35367754Smsmith * The walk of this method is complete. 35467754Smsmith */ 35567754Smsmith ParserState->Aml = ParserState->AmlEnd; 35667754Smsmith Status = AE_CTRL_TERMINATE; 35767754Smsmith break; 35867754Smsmith 35991116Smsmith case AE_CTRL_BREAK: 36067754Smsmith 36191116Smsmith ParserState->Aml = WalkState->AmlLastWhile; 36291116Smsmith WalkState->ControlState->Common.Value = FALSE; 36391116Smsmith Status = AE_CTRL_BREAK; 36491116Smsmith break; 36567754Smsmith 36691116Smsmith case AE_CTRL_CONTINUE: 36767754Smsmith 36867754Smsmith ParserState->Aml = WalkState->AmlLastWhile; 36991116Smsmith Status = AE_CTRL_CONTINUE; 37067754Smsmith break; 37167754Smsmith 37291116Smsmith case AE_CTRL_PENDING: 37367754Smsmith 37491116Smsmith ParserState->Aml = WalkState->AmlLastWhile; 37591116Smsmith break; 37691116Smsmith 377102550Siwasaki#if 0 378102550Siwasaki case AE_CTRL_SKIP: 37991116Smsmith 380102550Siwasaki ParserState->Aml = ParserState->Scope->ParseScope.PkgEnd; 381102550Siwasaki Status = AE_OK; 382102550Siwasaki break; 383102550Siwasaki#endif 384102550Siwasaki 38567754Smsmith case AE_CTRL_TRUE: 38683174Smsmith /* 38783174Smsmith * Predicate of an IF was true, and we are at the matching ELSE. 38883174Smsmith * Just close out this package 38983174Smsmith */ 39091116Smsmith ParserState->Aml = AcpiPsGetNextPackageEnd (ParserState); 391167802Sjkim Status = AE_CTRL_PENDING; 39267754Smsmith break; 39367754Smsmith 39467754Smsmith case AE_CTRL_FALSE: 39567754Smsmith /* 39667754Smsmith * Either an IF/WHILE Predicate was false or we encountered a BREAK 397241973Sjkim * opcode. In both cases, we do not execute the rest of the 39867754Smsmith * package; We simply close out the parent (finishing the walk of 39967754Smsmith * this branch of the tree) and continue execution at the parent 40067754Smsmith * level. 40167754Smsmith */ 40267754Smsmith ParserState->Aml = ParserState->Scope->ParseScope.PkgEnd; 40367754Smsmith 40467754Smsmith /* In the case of a BREAK, just force a predicate (if any) to FALSE */ 40567754Smsmith 40667754Smsmith WalkState->ControlState->Common.Value = FALSE; 40767754Smsmith Status = AE_CTRL_END; 40867754Smsmith break; 40967754Smsmith 41067754Smsmith case AE_CTRL_TRANSFER: 41167754Smsmith 412151937Sjkim /* A method call (invocation) -- transfer control */ 413151937Sjkim 41467754Smsmith Status = AE_CTRL_TRANSFER; 41567754Smsmith WalkState->PrevOp = Op; 41667754Smsmith WalkState->MethodCallOp = Op; 41799679Siwasaki WalkState->MethodCallNode = (Op->Common.Value.Arg)->Common.Node; 41867754Smsmith 41967754Smsmith /* Will return value (if any) be used by the caller? */ 42067754Smsmith 42167754Smsmith WalkState->ReturnUsed = AcpiDsIsResultUsed (Op, WalkState); 42267754Smsmith break; 42367754Smsmith 42467754Smsmith default: 425151937Sjkim 42667754Smsmith Status = CallbackStatus; 42767754Smsmith if ((CallbackStatus & AE_CODE_MASK) == AE_CODE_CONTROL) 42867754Smsmith { 42967754Smsmith Status = AE_OK; 43067754Smsmith } 43167754Smsmith break; 43267754Smsmith } 43367754Smsmith 43467754Smsmith return_ACPI_STATUS (Status); 43567754Smsmith} 43667754Smsmith 43767754Smsmith 43867754Smsmith/******************************************************************************* 43967754Smsmith * 44067754Smsmith * FUNCTION: AcpiPsParseAml 44167754Smsmith * 442151937Sjkim * PARAMETERS: WalkState - Current state 44367754Smsmith * 44483174Smsmith * 44567754Smsmith * RETURN: Status 44667754Smsmith * 44767754Smsmith * DESCRIPTION: Parse raw AML and return a tree of ops 44867754Smsmith * 44967754Smsmith ******************************************************************************/ 45067754Smsmith 45167754SmsmithACPI_STATUS 45267754SmsmithAcpiPsParseAml ( 45384491Smsmith ACPI_WALK_STATE *WalkState) 45467754Smsmith{ 45567754Smsmith ACPI_STATUS Status; 45687031Smsmith ACPI_THREAD_STATE *Thread; 45787031Smsmith ACPI_THREAD_STATE *PrevWalkList = AcpiGbl_CurrentWalkList; 45884491Smsmith ACPI_WALK_STATE *PreviousWalkState; 45967754Smsmith 46067754Smsmith 461167802Sjkim ACPI_FUNCTION_TRACE (PsParseAml); 46267754Smsmith 463151937Sjkim ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, 464151937Sjkim "Entered with WalkState=%p Aml=%p size=%X\n", 465151937Sjkim WalkState, WalkState->ParserState.Aml, 466151937Sjkim WalkState->ParserState.AmlSize)); 46767754Smsmith 468193267Sjkim if (!WalkState->ParserState.Aml) 469193267Sjkim { 470193267Sjkim return_ACPI_STATUS (AE_NULL_OBJECT); 471193267Sjkim } 47267754Smsmith 47387031Smsmith /* Create and initialize a new thread state */ 47467754Smsmith 47587031Smsmith Thread = AcpiUtCreateThreadState (); 47687031Smsmith if (!Thread) 47787031Smsmith { 478193267Sjkim if (WalkState->MethodDesc) 479193267Sjkim { 480193267Sjkim /* Executing a control method - additional cleanup */ 481193267Sjkim 482193267Sjkim AcpiDsTerminateControlMethod (WalkState->MethodDesc, WalkState); 483193267Sjkim } 484193267Sjkim 485167802Sjkim AcpiDsDeleteWalkState (WalkState); 48687031Smsmith return_ACPI_STATUS (AE_NO_MEMORY); 48787031Smsmith } 48867754Smsmith 48987031Smsmith WalkState->Thread = Thread; 490167802Sjkim 491167802Sjkim /* 492167802Sjkim * If executing a method, the starting SyncLevel is this method's 493167802Sjkim * SyncLevel 494167802Sjkim */ 495167802Sjkim if (WalkState->MethodDesc) 496167802Sjkim { 497306536Sjkim WalkState->Thread->CurrentSyncLevel = 498306536Sjkim WalkState->MethodDesc->Method.SyncLevel; 499167802Sjkim } 500167802Sjkim 50187031Smsmith AcpiDsPushWalkState (WalkState, Thread); 50267754Smsmith 50391116Smsmith /* 50491116Smsmith * This global allows the AML debugger to get a handle to the currently 50591116Smsmith * executing control method. 50667754Smsmith */ 50787031Smsmith AcpiGbl_CurrentWalkList = Thread; 50867754Smsmith 50967754Smsmith /* 510241973Sjkim * Execute the walk loop as long as there is a valid Walk State. This 51167754Smsmith * handles nested control method invocations without recursion. 51267754Smsmith */ 51382367Smsmith ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "State=%p\n", WalkState)); 51467754Smsmith 51583174Smsmith Status = AE_OK; 51667754Smsmith while (WalkState) 51767754Smsmith { 51867754Smsmith if (ACPI_SUCCESS (Status)) 51967754Smsmith { 52084491Smsmith /* 52184491Smsmith * The ParseLoop executes AML until the method terminates 52284491Smsmith * or calls another method. 52384491Smsmith */ 52467754Smsmith Status = AcpiPsParseLoop (WalkState); 52567754Smsmith } 52667754Smsmith 52783174Smsmith ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, 528114237Snjl "Completed one call to walk loop, %s State=%p\n", 529107325Siwasaki AcpiFormatException (Status), WalkState)); 53067754Smsmith 53167754Smsmith if (Status == AE_CTRL_TRANSFER) 53267754Smsmith { 53367754Smsmith /* 53467754Smsmith * A method call was detected. 53567754Smsmith * Transfer control to the called control method 53667754Smsmith */ 53787031Smsmith Status = AcpiDsCallControlMethod (Thread, WalkState, NULL); 538167802Sjkim if (ACPI_FAILURE (Status)) 539167802Sjkim { 540167802Sjkim Status = AcpiDsMethodError (Status, WalkState); 541167802Sjkim } 54267754Smsmith 54367754Smsmith /* 544306536Sjkim * If the transfer to the new method method call worked 545306536Sjkim *, a new walk state was created -- get it 54667754Smsmith */ 54787031Smsmith WalkState = AcpiDsGetCurrentWalkState (Thread); 54867754Smsmith continue; 54967754Smsmith } 55067754Smsmith else if (Status == AE_CTRL_TERMINATE) 55167754Smsmith { 55267754Smsmith Status = AE_OK; 55367754Smsmith } 554138287Smarks else if ((Status != AE_OK) && (WalkState->MethodDesc)) 555107325Siwasaki { 556167802Sjkim /* Either the method parse or actual execution failed */ 557167802Sjkim 558167802Sjkim ACPI_ERROR_METHOD ("Method parse/execution failed", 559114237Snjl WalkState->MethodNode, NULL, Status); 560127175Snjl 561127175Snjl /* Check for possible multi-thread reentrancy problem */ 562127175Snjl 563127175Snjl if ((Status == AE_ALREADY_EXISTS) && 564306536Sjkim (!(WalkState->MethodDesc->Method.InfoFlags & 565306536Sjkim ACPI_METHOD_SERIALIZED))) 566127175Snjl { 567127175Snjl /* 568217365Sjkim * Method is not serialized and tried to create an object 569217365Sjkim * twice. The probable cause is that the method cannot 570217365Sjkim * handle reentrancy. Mark as "pending serialized" now, and 571217365Sjkim * then mark "serialized" when the last thread exits. 572127175Snjl */ 573217365Sjkim WalkState->MethodDesc->Method.InfoFlags |= 574217365Sjkim ACPI_METHOD_SERIALIZED_PENDING; 575127175Snjl } 576107325Siwasaki } 57767754Smsmith 57867754Smsmith /* We are done with this walk, move on to the parent if any */ 57967754Smsmith 58087031Smsmith WalkState = AcpiDsPopWalkState (Thread); 58167754Smsmith 58267754Smsmith /* Reset the current scope to the beginning of scope stack */ 58367754Smsmith 58467754Smsmith AcpiDsScopeStackClear (WalkState); 58567754Smsmith 58667754Smsmith /* 587167802Sjkim * If we just returned from the execution of a control method or if we 588167802Sjkim * encountered an error during the method parse phase, there's lots of 589167802Sjkim * cleanup to do 59067754Smsmith */ 591306536Sjkim if (((WalkState->ParseFlags & ACPI_PARSE_MODE_MASK) == 592306536Sjkim ACPI_PARSE_EXECUTE) || 593167802Sjkim (ACPI_FAILURE (Status))) 59467754Smsmith { 595167802Sjkim AcpiDsTerminateControlMethod (WalkState->MethodDesc, WalkState); 59667754Smsmith } 59767754Smsmith 59883174Smsmith /* Delete this walk state and all linked control states */ 59967754Smsmith 60084491Smsmith AcpiPsCleanupScope (&WalkState->ParserState); 60184491Smsmith PreviousWalkState = WalkState; 60284491Smsmith 603151937Sjkim ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, 604151937Sjkim "ReturnValue=%p, ImplicitValue=%p State=%p\n", 605151937Sjkim WalkState->ReturnDesc, WalkState->ImplicitReturnObj, WalkState)); 60684491Smsmith 60783174Smsmith /* Check if we have restarted a preempted walk */ 60867754Smsmith 60987031Smsmith WalkState = AcpiDsGetCurrentWalkState (Thread); 61084491Smsmith if (WalkState) 61167754Smsmith { 61284491Smsmith if (ACPI_SUCCESS (Status)) 61384491Smsmith { 61484491Smsmith /* 61591116Smsmith * There is another walk state, restart it. 61691116Smsmith * If the method return value is not used by the parent, 61784491Smsmith * The object is deleted 61884491Smsmith */ 619151937Sjkim if (!PreviousWalkState->ReturnDesc) 620151937Sjkim { 621193267Sjkim /* 622193267Sjkim * In slack mode execution, if there is no return value 623193267Sjkim * we should implicitly return zero (0) as a default value. 624193267Sjkim */ 625193267Sjkim if (AcpiGbl_EnableInterpreterSlack && 626193267Sjkim !PreviousWalkState->ImplicitReturnObj) 627193267Sjkim { 628193267Sjkim PreviousWalkState->ImplicitReturnObj = 629199337Sjkim AcpiUtCreateIntegerObject ((UINT64) 0); 630193267Sjkim if (!PreviousWalkState->ImplicitReturnObj) 631193267Sjkim { 632193267Sjkim return_ACPI_STATUS (AE_NO_MEMORY); 633193267Sjkim } 634193267Sjkim } 635193267Sjkim 636193267Sjkim /* Restart the calling control method */ 637193267Sjkim 638151937Sjkim Status = AcpiDsRestartControlMethod (WalkState, 639306536Sjkim PreviousWalkState->ImplicitReturnObj); 640151937Sjkim } 641151937Sjkim else 642151937Sjkim { 643151937Sjkim /* 644151937Sjkim * We have a valid return value, delete any implicit 645151937Sjkim * return value. 646151937Sjkim */ 647151937Sjkim AcpiDsClearImplicitReturn (PreviousWalkState); 648151937Sjkim 649151937Sjkim Status = AcpiDsRestartControlMethod (WalkState, 650306536Sjkim PreviousWalkState->ReturnDesc); 651151937Sjkim } 65299679Siwasaki if (ACPI_SUCCESS (Status)) 65399679Siwasaki { 65499679Siwasaki WalkState->WalkType |= ACPI_WALK_METHOD_RESTART; 65599679Siwasaki } 65684491Smsmith } 65791116Smsmith else 65891116Smsmith { 659193267Sjkim /* On error, delete any return object or implicit return */ 66091116Smsmith 66191116Smsmith AcpiUtRemoveReference (PreviousWalkState->ReturnDesc); 662193267Sjkim AcpiDsClearImplicitReturn (PreviousWalkState); 66391116Smsmith } 66467754Smsmith } 66567754Smsmith 66667754Smsmith /* 66767754Smsmith * Just completed a 1st-level method, save the final internal return 66867754Smsmith * value (if any) 66967754Smsmith */ 67084491Smsmith else if (PreviousWalkState->CallerReturnDesc) 67167754Smsmith { 672151937Sjkim if (PreviousWalkState->ImplicitReturnObj) 673151937Sjkim { 674151937Sjkim *(PreviousWalkState->CallerReturnDesc) = 675151937Sjkim PreviousWalkState->ImplicitReturnObj; 676151937Sjkim } 677151937Sjkim else 678151937Sjkim { 679151937Sjkim /* NULL if no return value */ 680151937Sjkim 681151937Sjkim *(PreviousWalkState->CallerReturnDesc) = 682151937Sjkim PreviousWalkState->ReturnDesc; 683151937Sjkim } 68467754Smsmith } 685151937Sjkim else 68667754Smsmith { 687151937Sjkim if (PreviousWalkState->ReturnDesc) 688151937Sjkim { 689151937Sjkim /* Caller doesn't want it, must delete it */ 69067754Smsmith 691151937Sjkim AcpiUtRemoveReference (PreviousWalkState->ReturnDesc); 692151937Sjkim } 693151937Sjkim if (PreviousWalkState->ImplicitReturnObj) 694151937Sjkim { 695151937Sjkim /* Caller doesn't want it, must delete it */ 696151937Sjkim 697151937Sjkim AcpiUtRemoveReference (PreviousWalkState->ImplicitReturnObj); 698151937Sjkim } 69967754Smsmith } 70084491Smsmith 70184491Smsmith AcpiDsDeleteWalkState (PreviousWalkState); 70267754Smsmith } 70367754Smsmith 70467754Smsmith /* Normal exit */ 70567754Smsmith 70687031Smsmith AcpiExReleaseAllMutexes (Thread); 70799679Siwasaki AcpiUtDeleteGenericState (ACPI_CAST_PTR (ACPI_GENERIC_STATE, Thread)); 70867754Smsmith AcpiGbl_CurrentWalkList = PrevWalkList; 70967754Smsmith return_ACPI_STATUS (Status); 71067754Smsmith} 711