117680Spst/****************************************************************************** 239300Sfenner * 317680Spst * Module Name: psparse - Parser top level AML parse routines 417680Spst * 517680Spst *****************************************************************************/ 617680Spst 717680Spst/* 817680Spst * Copyright (C) 2000 - 2016, Intel Corp. 917680Spst * All rights reserved. 1017680Spst * 1117680Spst * Redistribution and use in source and binary forms, with or without 1217680Spst * modification, are permitted provided that the following conditions 1317680Spst * are met: 1417680Spst * 1. Redistributions of source code must retain the above copyright 1517680Spst * notice, this list of conditions, and the following disclaimer, 1617680Spst * without modification. 1717680Spst * 2. Redistributions in binary form must reproduce at minimum a disclaimer 1817680Spst * substantially similar to the "NO WARRANTY" disclaimer below 1917680Spst * ("Disclaimer") and any redistribution must be conditioned upon 2053146Sbrian * including a substantially similar Disclaimer requirement for further 2175118Sfenner * binary redistribution. 2275118Sfenner * 3. Neither the names of the above-listed copyright holders nor the names 2375118Sfenner * of any contributors may be used to endorse or promote products derived 2453146Sbrian * from this software without specific prior written permission. 2517680Spst * 2617680Spst * Alternatively, this software may be distributed under the terms of the 2775118Sfenner * GNU General Public License ("GPL") version 2 as published by the Free 2875118Sfenner * Software Foundation. 2975118Sfenner * 3075118Sfenner * NO WARRANTY 3175118Sfenner * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 3275118Sfenner * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 3375118Sfenner * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR 3417680Spst * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 35127675Sbms * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 36190207Srpaulo * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 3717680Spst * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3817680Spst * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 3956896Sfenner * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 4056896Sfenner * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 4156896Sfenner * POSSIBILITY OF SUCH DAMAGES. 4256896Sfenner */ 43127675Sbms 4417680Spst/* 4575118Sfenner * Parse the AML and build an operation tree as most interpreters, 4675118Sfenner * like Perl, do. Parsing is done by hand rather than with a YACC 4775118Sfenner * generated parser to tightly constrain stack and dynamic memory 4817680Spst * usage. At the same time, parsing is kept flexible and the code 4917680Spst * fairly compact by parsing based on a list of AML opcode 5017680Spst * templates in AmlOpInfo[] 5117680Spst */ 52146778Ssam 5317680Spst#include <contrib/dev/acpica/include/acpi.h> 5417680Spst#include <contrib/dev/acpica/include/accommon.h> 5556896Sfenner#include <contrib/dev/acpica/include/acparser.h> 5617680Spst#include <contrib/dev/acpica/include/acdispat.h> 5739300Sfenner#include <contrib/dev/acpica/include/amlcode.h> 5875118Sfenner#include <contrib/dev/acpica/include/acinterp.h> 5975118Sfenner 60146778Ssam#define _COMPONENT ACPI_PARSER 6117680Spst ACPI_MODULE_NAME ("psparse") 6275118Sfenner 6375118Sfenner 6475118Sfenner/******************************************************************************* 6575118Sfenner * 6675118Sfenner * FUNCTION: AcpiPsGetOpcodeSize 6717680Spst * 68127675Sbms * PARAMETERS: Opcode - An AML opcode 6917692Spst * 70127675Sbms * RETURN: Size of the opcode, in bytes (1 or 2) 71127675Sbms * 72127675Sbms * DESCRIPTION: Get the size of the current opcode. 73127675Sbms * 74127675Sbms ******************************************************************************/ 75127675Sbms 76127675SbmsUINT32 77146778SsamAcpiPsGetOpcodeSize ( 78146778Ssam UINT32 Opcode) 79127675Sbms{ 80127675Sbms 81127675Sbms /* Extended (2-byte) opcode if > 255 */ 82127675Sbms 83127675Sbms if (Opcode > 0x00FF) 84146778Ssam { 85146778Ssam return (2); 86146778Ssam } 87127675Sbms 88127675Sbms /* Otherwise, just a single byte opcode */ 89127675Sbms 90127675Sbms return (1); 91127675Sbms} 92127675Sbms 93127675Sbms 94127675Sbms/******************************************************************************* 95127675Sbms * 96127675Sbms * FUNCTION: AcpiPsPeekOpcode 97127675Sbms * 98127675Sbms * PARAMETERS: ParserState - A parser state object 99146778Ssam * 100127675Sbms * RETURN: Next AML opcode 101127675Sbms * 102127675Sbms * DESCRIPTION: Get next AML opcode (without incrementing AML pointer) 103127675Sbms * 104127675Sbms ******************************************************************************/ 105127675Sbms 106146778SsamUINT16 107146778SsamAcpiPsPeekOpcode ( 108146778Ssam ACPI_PARSE_STATE *ParserState) 109127675Sbms{ 110127675Sbms UINT8 *Aml; 111146778Ssam UINT16 Opcode; 112127675Sbms 113127675Sbms 114127675Sbms Aml = ParserState->Aml; 115127675Sbms Opcode = (UINT16) ACPI_GET8 (Aml); 116127675Sbms 11775118Sfenner if (Opcode == AML_EXTENDED_OP_PREFIX) 11875118Sfenner { 11975118Sfenner /* Extended opcode, get the second opcode byte */ 12075118Sfenner 12175118Sfenner Aml++; 12275118Sfenner Opcode = (UINT16) ((Opcode << 8) | ACPI_GET8 (Aml)); 12375118Sfenner } 12475118Sfenner 12575118Sfenner return (Opcode); 12675118Sfenner} 12775118Sfenner 12875118Sfenner 129127675Sbms/******************************************************************************* 130127675Sbms * 131127675Sbms * FUNCTION: AcpiPsCompleteThisOp 13275118Sfenner * 13338638Sthepish * PARAMETERS: WalkState - Current State 134127675Sbms * Op - Op to complete 135127675Sbms * 136127675Sbms * RETURN: Status 137127675Sbms * 138127675Sbms * DESCRIPTION: Perform any cleanup at the completion of an Op. 139127675Sbms * 140127675Sbms ******************************************************************************/ 141127675Sbms 142127675SbmsACPI_STATUS 143127675SbmsAcpiPsCompleteThisOp ( 144127675Sbms ACPI_WALK_STATE *WalkState, 145127675Sbms ACPI_PARSE_OBJECT *Op) 146127675Sbms{ 147127675Sbms ACPI_PARSE_OBJECT *Prev; 148127675Sbms ACPI_PARSE_OBJECT *Next; 149127675Sbms const ACPI_OPCODE_INFO *ParentInfo; 150127675Sbms ACPI_PARSE_OBJECT *ReplacementOp = NULL; 151127675Sbms ACPI_STATUS Status = AE_OK; 15238638Sthepish 15338638Sthepish 15475118Sfenner ACPI_FUNCTION_TRACE_PTR (PsCompleteThisOp, Op); 15575118Sfenner 15638638Sthepish 15738638Sthepish /* Check for null Op, can happen if AML code is corrupt */ 15838638Sthepish 15938638Sthepish if (!Op) 16038638Sthepish { 16138638Sthepish return_ACPI_STATUS (AE_OK); /* OK for now */ 16275118Sfenner } 16338638Sthepish 16438638Sthepish AcpiExStopTraceOpcode (Op, WalkState); 16575118Sfenner 16675118Sfenner /* Delete this op and the subtree below it if asked to */ 16775118Sfenner 16875118Sfenner if (((WalkState->ParseFlags & ACPI_PARSE_TREE_MASK) != ACPI_PARSE_DELETE_TREE) || 16975118Sfenner (WalkState->OpInfo->Class == AML_CLASS_ARGUMENT)) 17075118Sfenner { 17175118Sfenner return_ACPI_STATUS (AE_OK); 17275118Sfenner } 17375118Sfenner 17475118Sfenner /* Make sure that we only delete this subtree */ 17575118Sfenner 17675118Sfenner if (Op->Common.Parent) 17775118Sfenner { 17875118Sfenner Prev = Op->Common.Parent->Common.Value.Arg; 17975118Sfenner if (!Prev) 18075118Sfenner { 18175118Sfenner /* Nothing more to do */ 18275118Sfenner 18375118Sfenner goto Cleanup; 18475118Sfenner } 18575118Sfenner 18675118Sfenner /* 18738638Sthepish * Check if we need to replace the operator and its subtree 18875118Sfenner * with a return value op (placeholder op) 18975118Sfenner */ 19038638Sthepish ParentInfo = AcpiPsGetOpcodeInfo (Op->Common.Parent->Common.AmlOpcode); 19175118Sfenner 19275118Sfenner switch (ParentInfo->Class) 19375118Sfenner { 19475118Sfenner case AML_CLASS_CONTROL: 19575118Sfenner 19675118Sfenner break; 19775118Sfenner 19875118Sfenner case AML_CLASS_CREATE: 19975118Sfenner /* 20075118Sfenner * These opcodes contain TermArg operands. The current 20175118Sfenner * op must be replaced by a placeholder return op 20275118Sfenner */ 20375118Sfenner ReplacementOp = AcpiPsAllocOp ( 20475118Sfenner AML_INT_RETURN_VALUE_OP, Op->Common.Aml); 20575118Sfenner if (!ReplacementOp) 20675118Sfenner { 20775118Sfenner Status = AE_NO_MEMORY; 20875118Sfenner } 20975118Sfenner break; 210146778Ssam 21175118Sfenner case AML_CLASS_NAMED_OBJECT: 21275118Sfenner /* 21375118Sfenner * These opcodes contain TermArg operands. The current 21475118Sfenner * op must be replaced by a placeholder return op 21575118Sfenner */ 21675118Sfenner if ((Op->Common.Parent->Common.AmlOpcode == AML_REGION_OP) || 21775118Sfenner (Op->Common.Parent->Common.AmlOpcode == AML_DATA_REGION_OP) || 21875118Sfenner (Op->Common.Parent->Common.AmlOpcode == AML_BUFFER_OP) || 21975118Sfenner (Op->Common.Parent->Common.AmlOpcode == AML_PACKAGE_OP) || 22075118Sfenner (Op->Common.Parent->Common.AmlOpcode == AML_BANK_FIELD_OP) || 22175118Sfenner (Op->Common.Parent->Common.AmlOpcode == AML_VAR_PACKAGE_OP)) 22275118Sfenner { 22338638Sthepish ReplacementOp = AcpiPsAllocOp ( 22438638Sthepish AML_INT_RETURN_VALUE_OP, Op->Common.Aml); 22575118Sfenner if (!ReplacementOp) 22675118Sfenner { 22775118Sfenner Status = AE_NO_MEMORY; 22875118Sfenner } 22975118Sfenner } 23075118Sfenner else if ((Op->Common.Parent->Common.AmlOpcode == AML_NAME_OP) && 23175118Sfenner (WalkState->PassNumber <= ACPI_IMODE_LOAD_PASS2)) 23275118Sfenner { 23375118Sfenner if ((Op->Common.AmlOpcode == AML_BUFFER_OP) || 23475118Sfenner (Op->Common.AmlOpcode == AML_PACKAGE_OP) || 23575118Sfenner (Op->Common.AmlOpcode == AML_VAR_PACKAGE_OP)) 23675118Sfenner { 23775118Sfenner ReplacementOp = AcpiPsAllocOp (Op->Common.AmlOpcode, 23875118Sfenner Op->Common.Aml); 23975118Sfenner if (!ReplacementOp) 24075118Sfenner { 24175118Sfenner Status = AE_NO_MEMORY; 24275118Sfenner } 24375118Sfenner else 24475118Sfenner { 24575118Sfenner ReplacementOp->Named.Data = Op->Named.Data; 24675118Sfenner ReplacementOp->Named.Length = Op->Named.Length; 24775118Sfenner } 248147904Ssam } 249147904Ssam } 250147904Ssam break; 251147904Ssam 252147904Ssam default: 253147904Ssam 254147904Ssam ReplacementOp = AcpiPsAllocOp ( 255147904Ssam AML_INT_RETURN_VALUE_OP, Op->Common.Aml); 256147904Ssam if (!ReplacementOp) 257147904Ssam { 258147904Ssam Status = AE_NO_MEMORY; 259147904Ssam } 260147904Ssam } 261147904Ssam 262147904Ssam /* We must unlink this op from the parent tree */ 263147904Ssam 264147904Ssam if (Prev == Op) 26575118Sfenner { 26675118Sfenner /* This op is the first in the list */ 26775118Sfenner 26875118Sfenner if (ReplacementOp) 26975118Sfenner { 27075118Sfenner ReplacementOp->Common.Parent = Op->Common.Parent; 271147904Ssam ReplacementOp->Common.Value.Arg = NULL; 272147904Ssam ReplacementOp->Common.Node = Op->Common.Node; 273147904Ssam Op->Common.Parent->Common.Value.Arg = ReplacementOp; 274147904Ssam ReplacementOp->Common.Next = Op->Common.Next; 275147904Ssam } 276147904Ssam else 27775118Sfenner { 27875118Sfenner Op->Common.Parent->Common.Value.Arg = Op->Common.Next; 27975118Sfenner } 28075118Sfenner } 28175118Sfenner 28275118Sfenner /* Search the parent list */ 28375118Sfenner 28475118Sfenner else while (Prev) 28575118Sfenner { 28675118Sfenner /* Traverse all siblings in the parent's argument list */ 28775118Sfenner 28875118Sfenner Next = Prev->Common.Next; 289146778Ssam if (Next == Op) 290146778Ssam { 291146778Ssam if (ReplacementOp) 292146778Ssam { 293146778Ssam ReplacementOp->Common.Parent = Op->Common.Parent; 294146778Ssam ReplacementOp->Common.Value.Arg = NULL; 295146778Ssam ReplacementOp->Common.Node = Op->Common.Node; 296146778Ssam Prev->Common.Next = ReplacementOp; 297146778Ssam ReplacementOp->Common.Next = Op->Common.Next; 298146778Ssam Next = NULL; 299146778Ssam } 300146778Ssam else 301172686Smlaier { 302172686Smlaier Prev->Common.Next = Op->Common.Next; 303146778Ssam Next = NULL; 304172686Smlaier } 305172686Smlaier } 306172686Smlaier Prev = Next; 307172686Smlaier } 308172686Smlaier } 309172686Smlaier 310172686Smlaier 311172686SmlaierCleanup: 312172686Smlaier 313172686Smlaier /* Now we can actually delete the subtree rooted at Op */ 314172686Smlaier 315172686Smlaier AcpiPsDeleteParseTree (Op); 316146778Ssam return_ACPI_STATUS (Status); 317146778Ssam} 318146778Ssam 319146778Ssam 320146778Ssam/******************************************************************************* 321146778Ssam * 322146778Ssam * FUNCTION: AcpiPsNextParseState 323146778Ssam * 32475118Sfenner * PARAMETERS: WalkState - Current state 32575118Sfenner * Op - Current parse op 32675118Sfenner * CallbackStatus - Status from previous operation 32775118Sfenner * 32875118Sfenner * RETURN: Status 329127675Sbms * 33075118Sfenner * DESCRIPTION: Update the parser state based upon the return exception from 33175118Sfenner * the parser callback. 33275118Sfenner * 33375118Sfenner ******************************************************************************/ 33475118Sfenner 33575118SfennerACPI_STATUS 33675118SfennerAcpiPsNextParseState ( 33775118Sfenner ACPI_WALK_STATE *WalkState, 338146778Ssam ACPI_PARSE_OBJECT *Op, 339146778Ssam ACPI_STATUS CallbackStatus) 340146778Ssam{ 341146778Ssam ACPI_PARSE_STATE *ParserState = &WalkState->ParserState; 342146778Ssam ACPI_STATUS Status = AE_CTRL_PENDING; 343146778Ssam 344146778Ssam 34575118Sfenner ACPI_FUNCTION_TRACE_PTR (PsNextParseState, Op); 34675118Sfenner 34775118Sfenner 34875118Sfenner switch (CallbackStatus) 34975118Sfenner { 35075118Sfenner case AE_CTRL_TERMINATE: 35175118Sfenner /* 35275118Sfenner * A control method was terminated via a RETURN statement. 35375118Sfenner * The walk of this method is complete. 35475118Sfenner */ 35575118Sfenner ParserState->Aml = ParserState->AmlEnd; 35675118Sfenner Status = AE_CTRL_TERMINATE; 35775118Sfenner break; 35875118Sfenner 35975118Sfenner case AE_CTRL_BREAK: 36075118Sfenner 36175118Sfenner ParserState->Aml = WalkState->AmlLastWhile; 36275118Sfenner WalkState->ControlState->Common.Value = FALSE; 363147904Ssam Status = AE_CTRL_BREAK; 364147904Ssam break; 365147904Ssam 366147904Ssam case AE_CTRL_CONTINUE: 367147904Ssam 368147904Ssam ParserState->Aml = WalkState->AmlLastWhile; 369147904Ssam Status = AE_CTRL_CONTINUE; 370147904Ssam break; 371147904Ssam 372147904Ssam case AE_CTRL_PENDING: 37338638Sthepish 37438638Sthepish ParserState->Aml = WalkState->AmlLastWhile; 37538638Sthepish break; 37638638Sthepish 37738638Sthepish#if 0 37838638Sthepish case AE_CTRL_SKIP: 37938638Sthepish 380146778Ssam ParserState->Aml = ParserState->Scope->ParseScope.PkgEnd; 381146778Ssam Status = AE_OK; 382146778Ssam break; 383146778Ssam#endif 384146778Ssam 385146778Ssam case AE_CTRL_TRUE: 38638638Sthepish /* 38738638Sthepish * Predicate of an IF was true, and we are at the matching ELSE. 38838638Sthepish * Just close out this package 38938638Sthepish */ 39038638Sthepish ParserState->Aml = AcpiPsGetNextPackageEnd (ParserState); 39138638Sthepish Status = AE_CTRL_PENDING; 39238638Sthepish break; 39338638Sthepish 394146778Ssam case AE_CTRL_FALSE: 395146778Ssam /* 396146778Ssam * Either an IF/WHILE Predicate was false or we encountered a BREAK 397146778Ssam * opcode. In both cases, we do not execute the rest of the 398146778Ssam * package; We simply close out the parent (finishing the walk of 39938638Sthepish * this branch of the tree) and continue execution at the parent 40038638Sthepish * level. 40175118Sfenner */ 40275118Sfenner ParserState->Aml = ParserState->Scope->ParseScope.PkgEnd; 40375118Sfenner 40475118Sfenner /* In the case of a BREAK, just force a predicate (if any) to FALSE */ 40575118Sfenner 40675118Sfenner WalkState->ControlState->Common.Value = FALSE; 40775118Sfenner Status = AE_CTRL_END; 40875118Sfenner break; 40975118Sfenner 41038638Sthepish case AE_CTRL_TRANSFER: 41175118Sfenner 41275118Sfenner /* A method call (invocation) -- transfer control */ 41375118Sfenner 41475118Sfenner Status = AE_CTRL_TRANSFER; 415146778Ssam WalkState->PrevOp = Op; 41675118Sfenner WalkState->MethodCallOp = Op; 41775118Sfenner WalkState->MethodCallNode = (Op->Common.Value.Arg)->Common.Node; 418146778Ssam 41975118Sfenner /* Will return value (if any) be used by the caller? */ 42075118Sfenner 42175118Sfenner WalkState->ReturnUsed = AcpiDsIsResultUsed (Op, WalkState); 422146778Ssam break; 42338638Sthepish 42475118Sfenner default: 42556896Sfenner 426127675Sbms Status = CallbackStatus; 42717680Spst if ((CallbackStatus & AE_CODE_MASK) == AE_CODE_CONTROL) 428127675Sbms { 42975118Sfenner Status = AE_OK; 43075118Sfenner } 43138638Sthepish break; 432127675Sbms } 43317680Spst 434127675Sbms return_ACPI_STATUS (Status); 43532149Spst} 436146778Ssam 437127675Sbms 43832149Spst/******************************************************************************* 439127675Sbms * 440127675Sbms * FUNCTION: AcpiPsParseAml 441127675Sbms * 44275118Sfenner * PARAMETERS: WalkState - Current state 443127675Sbms * 444127675Sbms * 445147904Ssam * RETURN: Status 446127675Sbms * 447147904Ssam * DESCRIPTION: Parse raw AML and return a tree of ops 448147904Ssam * 449147904Ssam ******************************************************************************/ 45075118Sfenner 451147904SsamACPI_STATUS 452147904SsamAcpiPsParseAml ( 453147904Ssam ACPI_WALK_STATE *WalkState) 454147904Ssam{ 455147904Ssam ACPI_STATUS Status; 456147904Ssam ACPI_THREAD_STATE *Thread; 457127675Sbms ACPI_THREAD_STATE *PrevWalkList = AcpiGbl_CurrentWalkList; 458127675Sbms ACPI_WALK_STATE *PreviousWalkState; 459127675Sbms 460127675Sbms 461147904Ssam ACPI_FUNCTION_TRACE (PsParseAml); 46275118Sfenner 463147904Ssam ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, 464147904Ssam "Entered with WalkState=%p Aml=%p size=%X\n", 465147904Ssam WalkState, WalkState->ParserState.Aml, 466147904Ssam WalkState->ParserState.AmlSize)); 46775118Sfenner 46875118Sfenner if (!WalkState->ParserState.Aml) 46975118Sfenner { 47075118Sfenner return_ACPI_STATUS (AE_NULL_OBJECT); 471127675Sbms } 472147904Ssam 473127675Sbms /* Create and initialize a new thread state */ 474127675Sbms 475146778Ssam Thread = AcpiUtCreateThreadState (); 476146778Ssam if (!Thread) 477146778Ssam { 47875118Sfenner if (WalkState->MethodDesc) 47975118Sfenner { 48075118Sfenner /* Executing a control method - additional cleanup */ 48175118Sfenner 48275118Sfenner AcpiDsTerminateControlMethod (WalkState->MethodDesc, WalkState); 48375118Sfenner } 48475118Sfenner 48556896Sfenner AcpiDsDeleteWalkState (WalkState); 48675118Sfenner return_ACPI_STATUS (AE_NO_MEMORY); 48775118Sfenner } 48875118Sfenner 48956896Sfenner WalkState->Thread = Thread; 49075118Sfenner 49175118Sfenner /* 49275118Sfenner * If executing a method, the starting SyncLevel is this method's 493146778Ssam * SyncLevel 494146778Ssam */ 495146778Ssam if (WalkState->MethodDesc) 49675118Sfenner { 49775118Sfenner WalkState->Thread->CurrentSyncLevel = 49875118Sfenner WalkState->MethodDesc->Method.SyncLevel; 49975118Sfenner } 50075118Sfenner 50175118Sfenner AcpiDsPushWalkState (WalkState, Thread); 50275118Sfenner 50375118Sfenner /* 504146778Ssam * This global allows the AML debugger to get a handle to the currently 505146778Ssam * executing control method. 50675118Sfenner */ 50775118Sfenner AcpiGbl_CurrentWalkList = Thread; 50875118Sfenner 50975118Sfenner /* 510140744Sbms * Execute the walk loop as long as there is a valid Walk State. This 511146778Ssam * handles nested control method invocations without recursion. 512146778Ssam */ 513146778Ssam ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "State=%p\n", WalkState)); 514127675Sbms 51575118Sfenner Status = AE_OK; 51656896Sfenner while (WalkState) 517127675Sbms { 51856896Sfenner if (ACPI_SUCCESS (Status)) 51956896Sfenner { 52032149Spst /* 52175118Sfenner * The ParseLoop executes AML until the method terminates 52275118Sfenner * or calls another method. 52375118Sfenner */ 52456896Sfenner Status = AcpiPsParseLoop (WalkState); 52575118Sfenner } 52675118Sfenner 52775118Sfenner ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, 52875118Sfenner "Completed one call to walk loop, %s State=%p\n", 52975118Sfenner AcpiFormatException (Status), WalkState)); 53075118Sfenner 531127675Sbms if (Status == AE_CTRL_TRANSFER) 532147904Ssam { 533127675Sbms /* 534127675Sbms * A method call was detected. 535147904Ssam * Transfer control to the called control method 536147904Ssam */ 537147904Ssam Status = AcpiDsCallControlMethod (Thread, WalkState, NULL); 538147904Ssam if (ACPI_FAILURE (Status)) 539147904Ssam { 54075118Sfenner Status = AcpiDsMethodError (Status, WalkState); 54175118Sfenner } 54275118Sfenner 54375118Sfenner /* 544147904Ssam * If the transfer to the new method method call worked 545147904Ssam *, a new walk state was created -- get it 546147904Ssam */ 547147904Ssam WalkState = AcpiDsGetCurrentWalkState (Thread); 548147904Ssam continue; 549147904Ssam } 550172686Smlaier else if (Status == AE_CTRL_TERMINATE) 551172686Smlaier { 552172686Smlaier Status = AE_OK; 553147904Ssam } 554147904Ssam else if ((Status != AE_OK) && (WalkState->MethodDesc)) 55575118Sfenner { 55675118Sfenner /* Either the method parse or actual execution failed */ 55775118Sfenner 558127675Sbms ACPI_ERROR_METHOD ("Method parse/execution failed", 559147904Ssam WalkState->MethodNode, NULL, Status); 560147904Ssam 561147904Ssam /* Check for possible multi-thread reentrancy problem */ 562147904Ssam 563147904Ssam if ((Status == AE_ALREADY_EXISTS) && 564147904Ssam (!(WalkState->MethodDesc->Method.InfoFlags & 56575118Sfenner ACPI_METHOD_SERIALIZED))) 56675118Sfenner { 56775118Sfenner /* 56875118Sfenner * Method is not serialized and tried to create an object 569127675Sbms * twice. The probable cause is that the method cannot 570147904Ssam * handle reentrancy. Mark as "pending serialized" now, and 571127675Sbms * then mark "serialized" when the last thread exits. 572127675Sbms */ 57375118Sfenner WalkState->MethodDesc->Method.InfoFlags |= 57475118Sfenner ACPI_METHOD_SERIALIZED_PENDING; 57556896Sfenner } 576127675Sbms } 577127675Sbms 578127675Sbms /* We are done with this walk, move on to the parent if any */ 579127675Sbms 580147904Ssam WalkState = AcpiDsPopWalkState (Thread); 58156896Sfenner 58238638Sthepish /* Reset the current scope to the beginning of scope stack */ 583127675Sbms 584127675Sbms AcpiDsScopeStackClear (WalkState); 585127675Sbms 586127675Sbms /* 58738638Sthepish * If we just returned from the execution of a control method or if we 58832149Spst * encountered an error during the method parse phase, there's lots of 58938638Sthepish * cleanup to do 59038638Sthepish */ 59175118Sfenner if (((WalkState->ParseFlags & ACPI_PARSE_MODE_MASK) == 59238638Sthepish ACPI_PARSE_EXECUTE) || 59375118Sfenner (ACPI_FAILURE (Status))) 59475118Sfenner { 59575118Sfenner AcpiDsTerminateControlMethod (WalkState->MethodDesc, WalkState); 59675118Sfenner } 597127675Sbms 59875118Sfenner /* Delete this walk state and all linked control states */ 59975118Sfenner 60075118Sfenner AcpiPsCleanupScope (&WalkState->ParserState); 60175118Sfenner PreviousWalkState = WalkState; 602147904Ssam 603147904Ssam ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, 604147904Ssam "ReturnValue=%p, ImplicitValue=%p State=%p\n", 605147904Ssam WalkState->ReturnDesc, WalkState->ImplicitReturnObj, WalkState)); 606147904Ssam 607147904Ssam /* Check if we have restarted a preempted walk */ 608147904Ssam 60956896Sfenner WalkState = AcpiDsGetCurrentWalkState (Thread); 610147904Ssam if (WalkState) 61175118Sfenner { 612147904Ssam if (ACPI_SUCCESS (Status)) 61375118Sfenner { 61475118Sfenner /* 61538638Sthepish * There is another walk state, restart it. 61656896Sfenner * If the method return value is not used by the parent, 61775118Sfenner * The object is deleted 61875118Sfenner */ 619127675Sbms if (!PreviousWalkState->ReturnDesc) 620147904Ssam { 621146778Ssam /* 622146778Ssam * In slack mode execution, if there is no return value 62375118Sfenner * we should implicitly return zero (0) as a default value. 624127675Sbms */ 625146778Ssam if (AcpiGbl_EnableInterpreterSlack && 626146778Ssam !PreviousWalkState->ImplicitReturnObj) 62775118Sfenner { 628127675Sbms PreviousWalkState->ImplicitReturnObj = 62975118Sfenner AcpiUtCreateIntegerObject ((UINT64) 0); 63075118Sfenner if (!PreviousWalkState->ImplicitReturnObj) 63175118Sfenner { 63275118Sfenner return_ACPI_STATUS (AE_NO_MEMORY); 63375118Sfenner } 63456896Sfenner } 635127675Sbms 636127675Sbms /* Restart the calling control method */ 637147904Ssam 638127675Sbms Status = AcpiDsRestartControlMethod (WalkState, 63956896Sfenner PreviousWalkState->ImplicitReturnObj); 64075118Sfenner } 641127675Sbms else 642127675Sbms { 643147904Ssam /* 644127675Sbms * We have a valid return value, delete any implicit 64575118Sfenner * return value. 64656896Sfenner */ 64756896Sfenner AcpiDsClearImplicitReturn (PreviousWalkState); 648127675Sbms 649147904Ssam Status = AcpiDsRestartControlMethod (WalkState, 650146778Ssam PreviousWalkState->ReturnDesc); 651127675Sbms } 652127675Sbms if (ACPI_SUCCESS (Status)) 653127675Sbms { 654146778Ssam WalkState->WalkType |= ACPI_WALK_METHOD_RESTART; 655127675Sbms } 656146778Ssam } 657127675Sbms else 658127675Sbms { 659127675Sbms /* On error, delete any return object or implicit return */ 660146778Ssam 661127675Sbms AcpiUtRemoveReference (PreviousWalkState->ReturnDesc); 662146778Ssam AcpiDsClearImplicitReturn (PreviousWalkState); 663127675Sbms } 66456896Sfenner } 66556896Sfenner 66656896Sfenner /* 66756896Sfenner * Just completed a 1st-level method, save the final internal return 668127675Sbms * value (if any) 669127675Sbms */ 67056896Sfenner else if (PreviousWalkState->CallerReturnDesc) 67156896Sfenner { 67256896Sfenner if (PreviousWalkState->ImplicitReturnObj) 67356896Sfenner { 67456896Sfenner *(PreviousWalkState->CallerReturnDesc) = 67556896Sfenner PreviousWalkState->ImplicitReturnObj; 676127675Sbms } 677127675Sbms else 678147904Ssam { 679127675Sbms /* NULL if no return value */ 68056896Sfenner 68156896Sfenner *(PreviousWalkState->CallerReturnDesc) = 68256896Sfenner PreviousWalkState->ReturnDesc; 68356896Sfenner } 68456896Sfenner } 68575118Sfenner else 686127675Sbms { 687127675Sbms if (PreviousWalkState->ReturnDesc) 688147904Ssam { 689127675Sbms /* Caller doesn't want it, must delete it */ 69075118Sfenner 69175118Sfenner AcpiUtRemoveReference (PreviousWalkState->ReturnDesc); 69275118Sfenner } 69375118Sfenner if (PreviousWalkState->ImplicitReturnObj) 694127675Sbms { 695147904Ssam /* Caller doesn't want it, must delete it */ 696147904Ssam 697147904Ssam AcpiUtRemoveReference (PreviousWalkState->ImplicitReturnObj); 69875118Sfenner } 69975118Sfenner } 700127675Sbms 701127675Sbms AcpiDsDeleteWalkState (PreviousWalkState); 702147904Ssam } 703127675Sbms 70475118Sfenner /* Normal exit */ 70575118Sfenner 70675118Sfenner AcpiExReleaseAllMutexes (Thread); 70775118Sfenner AcpiUtDeleteGenericState (ACPI_CAST_PTR (ACPI_GENERIC_STATE, Thread)); 708127675Sbms AcpiGbl_CurrentWalkList = PrevWalkList; 70975118Sfenner return_ACPI_STATUS (Status); 71075118Sfenner} 711147904Ssam