Path: blob/main/sys/contrib/dev/acpica/components/dispatcher/dsmethod.c
48521 views
/******************************************************************************1*2* Module Name: dsmethod - Parser/Interpreter interface - control method parsing3*4*****************************************************************************/56/******************************************************************************7*8* 1. Copyright Notice9*10* Some or all of this work - Copyright (c) 1999 - 2025, Intel Corp.11* All rights reserved.12*13* 2. License14*15* 2.1. This is your license from Intel Corp. under its intellectual property16* rights. You may have additional license terms from the party that provided17* you this software, covering your right to use that party's intellectual18* property rights.19*20* 2.2. Intel grants, free of charge, to any person ("Licensee") obtaining a21* copy of the source code appearing in this file ("Covered Code") an22* irrevocable, perpetual, worldwide license under Intel's copyrights in the23* base code distributed originally by Intel ("Original Intel Code") to copy,24* make derivatives, distribute, use and display any portion of the Covered25* Code in any form, with the right to sublicense such rights; and26*27* 2.3. Intel grants Licensee a non-exclusive and non-transferable patent28* license (with the right to sublicense), under only those claims of Intel29* patents that are infringed by the Original Intel Code, to make, use, sell,30* offer to sell, and import the Covered Code and derivative works thereof31* solely to the minimum extent necessary to exercise the above copyright32* license, and in no event shall the patent license extend to any additions33* to or modifications of the Original Intel Code. No other license or right34* is granted directly or by implication, estoppel or otherwise;35*36* The above copyright and patent license is granted only if the following37* conditions are met:38*39* 3. Conditions40*41* 3.1. Redistribution of Source with Rights to Further Distribute Source.42* Redistribution of source code of any substantial portion of the Covered43* Code or modification with rights to further distribute source must include44* the above Copyright Notice, the above License, this list of Conditions,45* and the following Disclaimer and Export Compliance provision. In addition,46* Licensee must cause all Covered Code to which Licensee contributes to47* contain a file documenting the changes Licensee made to create that Covered48* Code and the date of any change. Licensee must include in that file the49* documentation of any changes made by any predecessor Licensee. Licensee50* must include a prominent statement that the modification is derived,51* directly or indirectly, from Original Intel Code.52*53* 3.2. Redistribution of Source with no Rights to Further Distribute Source.54* Redistribution of source code of any substantial portion of the Covered55* Code or modification without rights to further distribute source must56* include the following Disclaimer and Export Compliance provision in the57* documentation and/or other materials provided with distribution. In58* addition, Licensee may not authorize further sublicense of source of any59* portion of the Covered Code, and must include terms to the effect that the60* license from Licensee to its licensee is limited to the intellectual61* property embodied in the software Licensee provides to its licensee, and62* not to intellectual property embodied in modifications its licensee may63* make.64*65* 3.3. Redistribution of Executable. Redistribution in executable form of any66* substantial portion of the Covered Code or modification must reproduce the67* above Copyright Notice, and the following Disclaimer and Export Compliance68* provision in the documentation and/or other materials provided with the69* distribution.70*71* 3.4. Intel retains all right, title, and interest in and to the Original72* Intel Code.73*74* 3.5. Neither the name Intel nor any other trademark owned or controlled by75* Intel shall be used in advertising or otherwise to promote the sale, use or76* other dealings in products derived from or relating to the Covered Code77* without prior written authorization from Intel.78*79* 4. Disclaimer and Export Compliance80*81* 4.1. INTEL MAKES NO WARRANTY OF ANY KIND REGARDING ANY SOFTWARE PROVIDED82* HERE. ANY SOFTWARE ORIGINATING FROM INTEL OR DERIVED FROM INTEL SOFTWARE83* IS PROVIDED "AS IS," AND INTEL WILL NOT PROVIDE ANY SUPPORT, ASSISTANCE,84* INSTALLATION, TRAINING OR OTHER SERVICES. INTEL WILL NOT PROVIDE ANY85* UPDATES, ENHANCEMENTS OR EXTENSIONS. INTEL SPECIFICALLY DISCLAIMS ANY86* IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT AND FITNESS FOR A87* PARTICULAR PURPOSE.88*89* 4.2. IN NO EVENT SHALL INTEL HAVE ANY LIABILITY TO LICENSEE, ITS LICENSEES90* OR ANY OTHER THIRD PARTY, FOR ANY LOST PROFITS, LOST DATA, LOSS OF USE OR91* COSTS OF PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY INDIRECT,92* SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THIS AGREEMENT, UNDER ANY93* CAUSE OF ACTION OR THEORY OF LIABILITY, AND IRRESPECTIVE OF WHETHER INTEL94* HAS ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. THESE LIMITATIONS95* SHALL APPLY NOTWITHSTANDING THE FAILURE OF THE ESSENTIAL PURPOSE OF ANY96* LIMITED REMEDY.97*98* 4.3. Licensee shall not export, either directly or indirectly, any of this99* software or system incorporating such software without first obtaining any100* required license or other approval from the U. S. Department of Commerce or101* any other agency or department of the United States Government. In the102* event Licensee exports any such software from the United States or103* re-exports any such software from a foreign destination, Licensee shall104* ensure that the distribution and export/re-export of the software is in105* compliance with all laws, regulations, orders, or other restrictions of the106* U.S. Export Administration Regulations. Licensee agrees that neither it nor107* any of its subsidiaries will export/re-export any technical data, process,108* software, or service, directly or indirectly, to any country for which the109* United States government or any agency thereof requires an export license,110* other governmental approval, or letter of assurance, without first obtaining111* such license, approval or letter.112*113*****************************************************************************114*115* Alternatively, you may choose to be licensed under the terms of the116* following license:117*118* Redistribution and use in source and binary forms, with or without119* modification, are permitted provided that the following conditions120* are met:121* 1. Redistributions of source code must retain the above copyright122* notice, this list of conditions, and the following disclaimer,123* without modification.124* 2. Redistributions in binary form must reproduce at minimum a disclaimer125* substantially similar to the "NO WARRANTY" disclaimer below126* ("Disclaimer") and any redistribution must be conditioned upon127* including a substantially similar Disclaimer requirement for further128* binary redistribution.129* 3. Neither the names of the above-listed copyright holders nor the names130* of any contributors may be used to endorse or promote products derived131* from this software without specific prior written permission.132*133* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS134* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT135* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR136* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT137* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,138* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT139* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,140* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY141* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT142* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE143* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.144*145* Alternatively, you may choose to be licensed under the terms of the146* GNU General Public License ("GPL") version 2 as published by the Free147* Software Foundation.148*149*****************************************************************************/150151#include <contrib/dev/acpica/include/acpi.h>152#include <contrib/dev/acpica/include/accommon.h>153#include <contrib/dev/acpica/include/acdispat.h>154#include <contrib/dev/acpica/include/acinterp.h>155#include <contrib/dev/acpica/include/acnamesp.h>156#include <contrib/dev/acpica/include/acparser.h>157#include <contrib/dev/acpica/include/amlcode.h>158#include <contrib/dev/acpica/include/acdebug.h>159160161#define _COMPONENT ACPI_DISPATCHER162ACPI_MODULE_NAME ("dsmethod")163164/* Local prototypes */165166static ACPI_STATUS167AcpiDsDetectNamedOpcodes (168ACPI_WALK_STATE *WalkState,169ACPI_PARSE_OBJECT **OutOp);170171static ACPI_STATUS172AcpiDsCreateMethodMutex (173ACPI_OPERAND_OBJECT *MethodDesc);174175176/*******************************************************************************177*178* FUNCTION: AcpiDsAutoSerializeMethod179*180* PARAMETERS: Node - Namespace Node of the method181* ObjDesc - Method object attached to node182*183* RETURN: Status184*185* DESCRIPTION: Parse a control method AML to scan for control methods that186* need serialization due to the creation of named objects.187*188* NOTE: It is a bit of overkill to mark all such methods serialized, since189* there is only a problem if the method actually blocks during execution.190* A blocking operation is, for example, a Sleep() operation, or any access191* to an operation region. However, it is probably not possible to easily192* detect whether a method will block or not, so we simply mark all suspicious193* methods as serialized.194*195* NOTE2: This code is essentially a generic routine for parsing a single196* control method.197*198******************************************************************************/199200ACPI_STATUS201AcpiDsAutoSerializeMethod (202ACPI_NAMESPACE_NODE *Node,203ACPI_OPERAND_OBJECT *ObjDesc)204{205ACPI_STATUS Status;206ACPI_PARSE_OBJECT *Op = NULL;207ACPI_WALK_STATE *WalkState;208209210ACPI_FUNCTION_TRACE_PTR (DsAutoSerializeMethod, Node);211212213ACPI_DEBUG_PRINT ((ACPI_DB_PARSE,214"Method auto-serialization parse [%4.4s] %p\n",215AcpiUtGetNodeName (Node), Node));216217/* Create/Init a root op for the method parse tree */218219Op = AcpiPsAllocOp (AML_METHOD_OP, ObjDesc->Method.AmlStart);220if (!Op)221{222return_ACPI_STATUS (AE_NO_MEMORY);223}224225AcpiPsSetName (Op, Node->Name.Integer);226Op->Common.Node = Node;227228/* Create and initialize a new walk state */229230WalkState = AcpiDsCreateWalkState (Node->OwnerId, NULL, NULL, NULL);231if (!WalkState)232{233AcpiPsFreeOp (Op);234return_ACPI_STATUS (AE_NO_MEMORY);235}236237Status = AcpiDsInitAmlWalk (WalkState, Op, Node,238ObjDesc->Method.AmlStart, ObjDesc->Method.AmlLength, NULL, 0);239if (ACPI_FAILURE (Status))240{241AcpiDsDeleteWalkState (WalkState);242AcpiPsFreeOp (Op);243return_ACPI_STATUS (Status);244}245246WalkState->DescendingCallback = AcpiDsDetectNamedOpcodes;247248/* Parse the method, scan for creation of named objects */249250Status = AcpiPsParseAml (WalkState);251252AcpiPsDeleteParseTree (Op);253return_ACPI_STATUS (Status);254}255256257/*******************************************************************************258*259* FUNCTION: AcpiDsDetectNamedOpcodes260*261* PARAMETERS: WalkState - Current state of the parse tree walk262* OutOp - Unused, required for parser interface263*264* RETURN: Status265*266* DESCRIPTION: Descending callback used during the loading of ACPI tables.267* Currently used to detect methods that must be marked serialized268* in order to avoid problems with the creation of named objects.269*270******************************************************************************/271272static ACPI_STATUS273AcpiDsDetectNamedOpcodes (274ACPI_WALK_STATE *WalkState,275ACPI_PARSE_OBJECT **OutOp)276{277278ACPI_FUNCTION_NAME (AcpiDsDetectNamedOpcodes);279280281/* We are only interested in opcodes that create a new name */282283if (!(WalkState->OpInfo->Flags & (AML_NAMED | AML_CREATE | AML_FIELD)))284{285return (AE_OK);286}287288/*289* At this point, we know we have a Named object opcode.290* Mark the method as serialized. Later code will create a mutex for291* this method to enforce serialization.292*293* Note, ACPI_METHOD_IGNORE_SYNC_LEVEL flag means that we will ignore the294* Sync Level mechanism for this method, even though it is now serialized.295* Otherwise, there can be conflicts with existing ASL code that actually296* uses sync levels.297*/298WalkState->MethodDesc->Method.SyncLevel = 0;299WalkState->MethodDesc->Method.InfoFlags |=300(ACPI_METHOD_SERIALIZED | ACPI_METHOD_IGNORE_SYNC_LEVEL);301302ACPI_DEBUG_PRINT ((ACPI_DB_INFO,303"Method serialized [%4.4s] %p - [%s] (%4.4X)\n",304WalkState->MethodNode->Name.Ascii, WalkState->MethodNode,305WalkState->OpInfo->Name, WalkState->Opcode));306307/* Abort the parse, no need to examine this method any further */308309return (AE_CTRL_TERMINATE);310}311312313/*******************************************************************************314*315* FUNCTION: AcpiDsMethodError316*317* PARAMETERS: Status - Execution status318* WalkState - Current state319*320* RETURN: Status321*322* DESCRIPTION: Called on method error. Invoke the global exception handler if323* present, dump the method data if the debugger is configured324*325* Note: Allows the exception handler to change the status code326*327******************************************************************************/328329ACPI_STATUS330AcpiDsMethodError (331ACPI_STATUS Status,332ACPI_WALK_STATE *WalkState)333{334UINT32 AmlOffset;335ACPI_NAME Name = 0;336337338ACPI_FUNCTION_ENTRY ();339340341/* Ignore AE_OK and control exception codes */342343if (ACPI_SUCCESS (Status) ||344(Status & AE_CODE_CONTROL))345{346return (Status);347}348349/* Invoke the global exception handler */350351if (AcpiGbl_ExceptionHandler)352{353/* Exit the interpreter, allow handler to execute methods */354355AcpiExExitInterpreter ();356357/*358* Handler can map the exception code to anything it wants, including359* AE_OK, in which case the executing method will not be aborted.360*/361AmlOffset = (UINT32) ACPI_PTR_DIFF (WalkState->Aml,362WalkState->ParserState.AmlStart);363364if (WalkState->MethodNode)365{366Name = WalkState->MethodNode->Name.Integer;367}368else if (WalkState->DeferredNode)369{370Name = WalkState->DeferredNode->Name.Integer;371}372373Status = AcpiGbl_ExceptionHandler (Status, Name,374WalkState->Opcode, AmlOffset, NULL);375AcpiExEnterInterpreter ();376}377378AcpiDsClearImplicitReturn (WalkState);379380if (ACPI_FAILURE (Status))381{382AcpiDsDumpMethodStack (Status, WalkState, WalkState->Op);383384/* Display method locals/args if debugger is present */385386#ifdef ACPI_DEBUGGER387AcpiDbDumpMethodInfo (Status, WalkState);388#endif389}390391return (Status);392}393394395/*******************************************************************************396*397* FUNCTION: AcpiDsCreateMethodMutex398*399* PARAMETERS: ObjDesc - The method object400*401* RETURN: Status402*403* DESCRIPTION: Create a mutex object for a serialized control method404*405******************************************************************************/406407static ACPI_STATUS408AcpiDsCreateMethodMutex (409ACPI_OPERAND_OBJECT *MethodDesc)410{411ACPI_OPERAND_OBJECT *MutexDesc;412ACPI_STATUS Status;413414415ACPI_FUNCTION_TRACE (DsCreateMethodMutex);416417418/* Create the new mutex object */419420MutexDesc = AcpiUtCreateInternalObject (ACPI_TYPE_MUTEX);421if (!MutexDesc)422{423return_ACPI_STATUS (AE_NO_MEMORY);424}425426/* Create the actual OS Mutex */427428Status = AcpiOsCreateMutex (&MutexDesc->Mutex.OsMutex);429if (ACPI_FAILURE (Status))430{431AcpiUtDeleteObjectDesc (MutexDesc);432return_ACPI_STATUS (Status);433}434435MutexDesc->Mutex.SyncLevel = MethodDesc->Method.SyncLevel;436MethodDesc->Method.Mutex = MutexDesc;437return_ACPI_STATUS (AE_OK);438}439440441/*******************************************************************************442*443* FUNCTION: AcpiDsBeginMethodExecution444*445* PARAMETERS: MethodNode - Node of the method446* ObjDesc - The method object447* WalkState - current state, NULL if not yet executing448* a method.449*450* RETURN: Status451*452* DESCRIPTION: Prepare a method for execution. Parses the method if necessary,453* increments the thread count, and waits at the method semaphore454* for clearance to execute.455*456******************************************************************************/457458ACPI_STATUS459AcpiDsBeginMethodExecution (460ACPI_NAMESPACE_NODE *MethodNode,461ACPI_OPERAND_OBJECT *ObjDesc,462ACPI_WALK_STATE *WalkState)463{464ACPI_STATUS Status = AE_OK;465466467ACPI_FUNCTION_TRACE_PTR (DsBeginMethodExecution, MethodNode);468469470if (!MethodNode)471{472return_ACPI_STATUS (AE_NULL_ENTRY);473}474475AcpiExStartTraceMethod (MethodNode, ObjDesc, WalkState);476477/* Prevent wraparound of thread count */478479if (ObjDesc->Method.ThreadCount == ACPI_UINT8_MAX)480{481ACPI_ERROR ((AE_INFO,482"Method reached maximum reentrancy limit (255)"));483return_ACPI_STATUS (AE_AML_METHOD_LIMIT);484}485486/*487* If this method is serialized, we need to acquire the method mutex.488*/489if (ObjDesc->Method.InfoFlags & ACPI_METHOD_SERIALIZED)490{491/*492* Create a mutex for the method if it is defined to be Serialized493* and a mutex has not already been created. We defer the mutex creation494* until a method is actually executed, to minimize the object count495*/496if (!ObjDesc->Method.Mutex)497{498Status = AcpiDsCreateMethodMutex (ObjDesc);499if (ACPI_FAILURE (Status))500{501return_ACPI_STATUS (Status);502}503}504505/*506* The CurrentSyncLevel (per-thread) must be less than or equal to507* the sync level of the method. This mechanism provides some508* deadlock prevention.509*510* If the method was auto-serialized, we just ignore the sync level511* mechanism, because auto-serialization of methods can interfere512* with ASL code that actually uses sync levels.513*514* Top-level method invocation has no walk state at this point515*/516if (WalkState &&517(!(ObjDesc->Method.InfoFlags & ACPI_METHOD_IGNORE_SYNC_LEVEL)) &&518(WalkState->Thread->CurrentSyncLevel >519ObjDesc->Method.Mutex->Mutex.SyncLevel))520{521ACPI_ERROR ((AE_INFO,522"Cannot acquire Mutex for method [%4.4s]"523", current SyncLevel is too large (%u)",524AcpiUtGetNodeName (MethodNode),525WalkState->Thread->CurrentSyncLevel));526527return_ACPI_STATUS (AE_AML_MUTEX_ORDER);528}529530/*531* Obtain the method mutex if necessary. Do not acquire mutex for a532* recursive call.533*/534if (!WalkState ||535!ObjDesc->Method.Mutex->Mutex.ThreadId ||536(WalkState->Thread->ThreadId !=537ObjDesc->Method.Mutex->Mutex.ThreadId))538{539/*540* Acquire the method mutex. This releases the interpreter if we541* block (and reacquires it before it returns)542*/543Status = AcpiExSystemWaitMutex (544ObjDesc->Method.Mutex->Mutex.OsMutex, ACPI_WAIT_FOREVER);545if (ACPI_FAILURE (Status))546{547return_ACPI_STATUS (Status);548}549550/* Update the mutex and walk info and save the original SyncLevel */551552if (WalkState)553{554ObjDesc->Method.Mutex->Mutex.OriginalSyncLevel =555WalkState->Thread->CurrentSyncLevel;556557ObjDesc->Method.Mutex->Mutex.ThreadId =558WalkState->Thread->ThreadId;559560/*561* Update the current SyncLevel only if this is not an auto-562* serialized method. In the auto case, we have to ignore563* the sync level for the method mutex (created for the564* auto-serialization) because we have no idea of what the565* sync level should be. Therefore, just ignore it.566*/567if (!(ObjDesc->Method.InfoFlags &568ACPI_METHOD_IGNORE_SYNC_LEVEL))569{570WalkState->Thread->CurrentSyncLevel =571ObjDesc->Method.SyncLevel;572}573}574else575{576ObjDesc->Method.Mutex->Mutex.OriginalSyncLevel =577ObjDesc->Method.Mutex->Mutex.SyncLevel;578579ObjDesc->Method.Mutex->Mutex.ThreadId =580AcpiOsGetThreadId ();581}582}583584/* Always increase acquisition depth */585586ObjDesc->Method.Mutex->Mutex.AcquisitionDepth++;587}588589/*590* Allocate an Owner ID for this method, only if this is the first thread591* to begin concurrent execution. We only need one OwnerId, even if the592* method is invoked recursively.593*/594if (!ObjDesc->Method.OwnerId)595{596Status = AcpiUtAllocateOwnerId (&ObjDesc->Method.OwnerId);597if (ACPI_FAILURE (Status))598{599goto Cleanup;600}601}602603/*604* Increment the method parse tree thread count since it has been605* reentered one more time (even if it is the same thread)606*/607ObjDesc->Method.ThreadCount++;608AcpiMethodCount++;609return_ACPI_STATUS (Status);610611612Cleanup:613/* On error, must release the method mutex (if present) */614615if (ObjDesc->Method.Mutex)616{617AcpiOsReleaseMutex (ObjDesc->Method.Mutex->Mutex.OsMutex);618}619return_ACPI_STATUS (Status);620}621622623/*******************************************************************************624*625* FUNCTION: AcpiDsCallControlMethod626*627* PARAMETERS: Thread - Info for this thread628* ThisWalkState - Current walk state629* Op - Current Op to be walked630*631* RETURN: Status632*633* DESCRIPTION: Transfer execution to a called control method634*635******************************************************************************/636637ACPI_STATUS638AcpiDsCallControlMethod (639ACPI_THREAD_STATE *Thread,640ACPI_WALK_STATE *ThisWalkState,641ACPI_PARSE_OBJECT *Op)642{643ACPI_STATUS Status;644ACPI_NAMESPACE_NODE *MethodNode;645ACPI_WALK_STATE *NextWalkState = NULL;646ACPI_OPERAND_OBJECT *ObjDesc;647ACPI_EVALUATE_INFO *Info;648649ACPI_FUNCTION_TRACE_PTR (DsCallControlMethod, ThisWalkState);650651ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,652"Calling method %p, currentstate=%p\n",653ThisWalkState->PrevOp, ThisWalkState));654655/*656* Get the namespace entry for the control method we are about to call657*/658MethodNode = ThisWalkState->MethodCallNode;659if (!MethodNode)660{661return_ACPI_STATUS (AE_NULL_ENTRY);662}663664ObjDesc = AcpiNsGetAttachedObject (MethodNode);665if (!ObjDesc)666{667return_ACPI_STATUS (AE_NULL_OBJECT);668}669670if (ThisWalkState->NumOperands < ObjDesc->Method.ParamCount)671{672ACPI_ERROR ((AE_INFO, "Missing argument(s) for method [%4.4s]",673AcpiUtGetNodeName (MethodNode)));674675return_ACPI_STATUS (AE_AML_TOO_FEW_ARGUMENTS);676}677678else if (ThisWalkState->NumOperands > ObjDesc->Method.ParamCount)679{680ACPI_ERROR ((AE_INFO, "Too many arguments for method [%4.4s]",681AcpiUtGetNodeName (MethodNode)));682683return_ACPI_STATUS (AE_AML_TOO_MANY_ARGUMENTS);684}685686687/* Init for new method, possibly wait on method mutex */688689Status = AcpiDsBeginMethodExecution (690MethodNode, ObjDesc, ThisWalkState);691if (ACPI_FAILURE (Status))692{693return_ACPI_STATUS (Status);694}695696/* Begin method parse/execution. Create a new walk state */697698NextWalkState = AcpiDsCreateWalkState (699ObjDesc->Method.OwnerId, NULL, ObjDesc, Thread);700if (!NextWalkState)701{702Status = AE_NO_MEMORY;703goto Cleanup;704}705706/*707* The resolved arguments were put on the previous walk state's operand708* stack. Operands on the previous walk state stack always709* start at index 0. Also, null terminate the list of arguments710*/711ThisWalkState->Operands [ThisWalkState->NumOperands] = NULL;712713/*714* Allocate and initialize the evaluation information block715* TBD: this is somewhat inefficient, should change interface to716* DsInitAmlWalk. For now, keeps this struct off the CPU stack717*/718Info = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_EVALUATE_INFO));719if (!Info)720{721Status = AE_NO_MEMORY;722goto PopWalkState;723}724725Info->Parameters = &ThisWalkState->Operands[0];726727Status = AcpiDsInitAmlWalk (NextWalkState, NULL, MethodNode,728ObjDesc->Method.AmlStart, ObjDesc->Method.AmlLength,729Info, ACPI_IMODE_EXECUTE);730731ACPI_FREE (Info);732if (ACPI_FAILURE (Status))733{734goto PopWalkState;735}736737NextWalkState->MethodNestingDepth = ThisWalkState->MethodNestingDepth + 1;738739/*740* Delete the operands on the previous walkstate operand stack741* (they were copied to new objects)742*/743AcpiDsClearOperands (ThisWalkState);744745ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,746"**** Begin nested execution of [%4.4s] **** WalkState=%p\n",747MethodNode->Name.Ascii, NextWalkState));748749ThisWalkState->MethodPathname = AcpiNsGetNormalizedPathname (MethodNode, TRUE);750ThisWalkState->MethodIsNested = TRUE;751752/* Optional object evaluation log */753754ACPI_DEBUG_PRINT_RAW ((ACPI_DB_EVALUATION,755"%-26s: %*s%s\n", " Nested method call",756NextWalkState->MethodNestingDepth * 3, " ",757&ThisWalkState->MethodPathname[1]));758759/* Invoke an internal method if necessary */760761if (ObjDesc->Method.InfoFlags & ACPI_METHOD_INTERNAL_ONLY)762{763Status = ObjDesc->Method.Dispatch.Implementation (NextWalkState);764if (Status == AE_OK)765{766Status = AE_CTRL_TERMINATE;767}768}769770return_ACPI_STATUS (Status);771772773PopWalkState:774775/* On error, pop the walk state to be deleted from thread */776777AcpiDsPopWalkState(Thread);778779Cleanup:780781/* On error, we must terminate the method properly */782783AcpiDsTerminateControlMethod (ObjDesc, NextWalkState);784AcpiDsDeleteWalkState (NextWalkState);785786return_ACPI_STATUS (Status);787}788789790/*******************************************************************************791*792* FUNCTION: AcpiDsRestartControlMethod793*794* PARAMETERS: WalkState - State for preempted method (caller)795* ReturnDesc - Return value from the called method796*797* RETURN: Status798*799* DESCRIPTION: Restart a method that was preempted by another (nested) method800* invocation. Handle the return value (if any) from the callee.801*802******************************************************************************/803804ACPI_STATUS805AcpiDsRestartControlMethod (806ACPI_WALK_STATE *WalkState,807ACPI_OPERAND_OBJECT *ReturnDesc)808{809ACPI_STATUS Status;810int SameAsImplicitReturn;811812813ACPI_FUNCTION_TRACE_PTR (DsRestartControlMethod, WalkState);814815816ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,817"****Restart [%4.4s] Op %p ReturnValueFromCallee %p\n",818AcpiUtGetNodeName (WalkState->MethodNode),819WalkState->MethodCallOp, ReturnDesc));820821ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,822" ReturnFromThisMethodUsed?=%X ResStack %p Walk %p\n",823WalkState->ReturnUsed,824WalkState->Results, WalkState));825826/* Did the called method return a value? */827828if (ReturnDesc)829{830/* Is the implicit return object the same as the return desc? */831832SameAsImplicitReturn = (WalkState->ImplicitReturnObj == ReturnDesc);833834/* Are we actually going to use the return value? */835836if (WalkState->ReturnUsed)837{838/* Save the return value from the previous method */839840Status = AcpiDsResultPush (ReturnDesc, WalkState);841if (ACPI_FAILURE (Status))842{843AcpiUtRemoveReference (ReturnDesc);844return_ACPI_STATUS (Status);845}846847/*848* Save as THIS method's return value in case it is returned849* immediately to yet another method850*/851WalkState->ReturnDesc = ReturnDesc;852}853854/*855* The following code is the optional support for the so-called856* "implicit return". Some AML code assumes that the last value of the857* method is "implicitly" returned to the caller, in the absence of an858* explicit return value.859*860* Just save the last result of the method as the return value.861*862* NOTE: this is optional because the ASL language does not actually863* support this behavior.864*/865else if (!AcpiDsDoImplicitReturn (ReturnDesc, WalkState, FALSE) ||866SameAsImplicitReturn)867{868/*869* Delete the return value if it will not be used by the870* calling method or remove one reference if the explicit return871* is the same as the implicit return value.872*/873AcpiUtRemoveReference (ReturnDesc);874}875}876877return_ACPI_STATUS (AE_OK);878}879880881/*******************************************************************************882*883* FUNCTION: AcpiDsTerminateControlMethod884*885* PARAMETERS: MethodDesc - Method object886* WalkState - State associated with the method887*888* RETURN: None889*890* DESCRIPTION: Terminate a control method. Delete everything that the method891* created, delete all locals and arguments, and delete the parse892* tree if requested.893*894* MUTEX: Interpreter is locked895*896******************************************************************************/897898void899AcpiDsTerminateControlMethod (900ACPI_OPERAND_OBJECT *MethodDesc,901ACPI_WALK_STATE *WalkState)902{903904ACPI_FUNCTION_TRACE_PTR (DsTerminateControlMethod, WalkState);905906907/* MethodDesc is required, WalkState is optional */908909if (!MethodDesc)910{911return_VOID;912}913914if (WalkState)915{916/* Delete all arguments and locals */917918AcpiDsMethodDataDeleteAll (WalkState);919920/*921* Delete any namespace objects created anywhere within the922* namespace by the execution of this method. Unless:923* 1) This method is a module-level executable code method, in which924* case we want make the objects permanent.925* 2) There are other threads executing the method, in which case we926* will wait until the last thread has completed.927*/928if (!(MethodDesc->Method.InfoFlags & ACPI_METHOD_MODULE_LEVEL) &&929(MethodDesc->Method.ThreadCount == 1))930{931/* Delete any direct children of (created by) this method */932933(void) AcpiExExitInterpreter ();934AcpiNsDeleteNamespaceSubtree (WalkState->MethodNode);935(void) AcpiExEnterInterpreter ();936937/*938* Delete any objects that were created by this method939* elsewhere in the namespace (if any were created).940* Use of the ACPI_METHOD_MODIFIED_NAMESPACE optimizes the941* deletion such that we don't have to perform an entire942* namespace walk for every control method execution.943*/944if (MethodDesc->Method.InfoFlags & ACPI_METHOD_MODIFIED_NAMESPACE)945{946(void) AcpiExExitInterpreter ();947AcpiNsDeleteNamespaceByOwner (MethodDesc->Method.OwnerId);948(void) AcpiExEnterInterpreter ();949MethodDesc->Method.InfoFlags &=950~ACPI_METHOD_MODIFIED_NAMESPACE;951}952}953954/*955* If method is serialized, release the mutex and restore the956* current sync level for this thread957*/958if (MethodDesc->Method.Mutex)959{960/* Acquisition Depth handles recursive calls */961962MethodDesc->Method.Mutex->Mutex.AcquisitionDepth--;963if (!MethodDesc->Method.Mutex->Mutex.AcquisitionDepth)964{965WalkState->Thread->CurrentSyncLevel =966MethodDesc->Method.Mutex->Mutex.OriginalSyncLevel;967968AcpiOsReleaseMutex (969MethodDesc->Method.Mutex->Mutex.OsMutex);970MethodDesc->Method.Mutex->Mutex.ThreadId = 0;971}972}973}974975/* Decrement the thread count on the method */976977if (MethodDesc->Method.ThreadCount)978{979MethodDesc->Method.ThreadCount--;980}981else982{983ACPI_ERROR ((AE_INFO,984"Invalid zero thread count in method"));985}986987/* Are there any other threads currently executing this method? */988989if (MethodDesc->Method.ThreadCount)990{991/*992* Additional threads. Do not release the OwnerId in this case,993* we immediately reuse it for the next thread executing this method994*/995ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,996"*** Completed execution of one thread, %u threads remaining\n",997MethodDesc->Method.ThreadCount));998}999else1000{1001/* This is the only executing thread for this method */10021003/*1004* Support to dynamically change a method from NotSerialized to1005* Serialized if it appears that the method is incorrectly written and1006* does not support multiple thread execution. The best example of this1007* is if such a method creates namespace objects and blocks. A second1008* thread will fail with an AE_ALREADY_EXISTS exception.1009*1010* This code is here because we must wait until the last thread exits1011* before marking the method as serialized.1012*/1013if (MethodDesc->Method.InfoFlags & ACPI_METHOD_SERIALIZED_PENDING)1014{1015if (WalkState)1016{1017ACPI_INFO ((1018"Marking method %4.4s as Serialized "1019"because of AE_ALREADY_EXISTS error",1020WalkState->MethodNode->Name.Ascii));1021}10221023/*1024* Method tried to create an object twice and was marked as1025* "pending serialized". The probable cause is that the method1026* cannot handle reentrancy.1027*1028* The method was created as NotSerialized, but it tried to create1029* a named object and then blocked, causing the second thread1030* entrance to begin and then fail. Workaround this problem by1031* marking the method permanently as Serialized when the last1032* thread exits here.1033*/1034MethodDesc->Method.InfoFlags &=1035~ACPI_METHOD_SERIALIZED_PENDING;10361037MethodDesc->Method.InfoFlags |=1038(ACPI_METHOD_SERIALIZED | ACPI_METHOD_IGNORE_SYNC_LEVEL);1039MethodDesc->Method.SyncLevel = 0;1040}10411042/* No more threads, we can free the OwnerId */10431044if (!(MethodDesc->Method.InfoFlags & ACPI_METHOD_MODULE_LEVEL))1045{1046AcpiUtReleaseOwnerId (&MethodDesc->Method.OwnerId);1047}1048}10491050AcpiExStopTraceMethod ((ACPI_NAMESPACE_NODE *) MethodDesc->Method.Node,1051MethodDesc, WalkState);10521053return_VOID;1054}105510561057