/******************************************************************************
*
* Module Name: dsmethod - Parser/Interpreter interface - control method parsing
*
*****************************************************************************/
/*
* Copyright (C) 2000 - 2016, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions, and the following disclaimer,
* without modification.
* 2. Redistributions in binary form must reproduce at minimum a disclaimer
* substantially similar to the "NO WARRANTY" disclaimer below
* ("Disclaimer") and any redistribution must be conditioned upon
* including a substantially similar Disclaimer requirement for further
* binary redistribution.
* 3. Neither the names of the above-listed copyright holders nor the names
* of any contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* Alternatively, this software may be distributed under the terms of the
* GNU General Public License ("GPL") version 2 as published by the Free
* Software Foundation.
*
* NO WARRANTY
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGES.
*/
#include "acpi.h"
#include "accommon.h"
#include "acdispat.h"
#include "acinterp.h"
#include "acnamesp.h"
#include "acparser.h"
#include "amlcode.h"
#include "acdebug.h"
ACPI_MODULE_NAME ("dsmethod")
/* Local prototypes */
static ACPI_STATUS
static ACPI_STATUS
/*******************************************************************************
*
* FUNCTION: AcpiDsAutoSerializeMethod
*
* PARAMETERS: Node - Namespace Node of the method
* ObjDesc - Method object attached to node
*
* RETURN: Status
*
* DESCRIPTION: Parse a control method AML to scan for control methods that
* need serialization due to the creation of named objects.
*
* NOTE: It is a bit of overkill to mark all such methods serialized, since
* there is only a problem if the method actually blocks during execution.
* A blocking operation is, for example, a Sleep() operation, or any access
* to an operation region. However, it is probably not possible to easily
* detect whether a method will block or not, so we simply mark all suspicious
* methods as serialized.
*
* NOTE2: This code is essentially a generic routine for parsing a single
* control method.
*
******************************************************************************/
{
"Method auto-serialization parse [%4.4s] %p\n",
if (!Op)
{
}
/* Create and initialize a new walk state */
if (!WalkState)
{
AcpiPsFreeOp (Op);
}
if (ACPI_FAILURE (Status))
{
AcpiPsFreeOp (Op);
}
/* Parse the method, scan for creation of named objects */
}
/*******************************************************************************
*
* FUNCTION: AcpiDsDetectNamedOpcodes
*
* PARAMETERS: WalkState - Current state of the parse tree walk
* OutOp - Unused, required for parser interface
*
* RETURN: Status
*
* DESCRIPTION: Descending callback used during the loading of ACPI tables.
* Currently used to detect methods that must be marked serialized
* in order to avoid problems with the creation of named objects.
*
******************************************************************************/
static ACPI_STATUS
{
/* We are only interested in opcodes that create a new name */
{
return (AE_OK);
}
/*
* At this point, we know we have a Named object opcode.
* Mark the method as serialized. Later code will create a mutex for
* this method to enforce serialization.
*
* Note, ACPI_METHOD_IGNORE_SYNC_LEVEL flag means that we will ignore the
* Sync Level mechanism for this method, even though it is now serialized.
* Otherwise, there can be conflicts with existing ASL code that actually
* uses sync levels.
*/
"Method serialized [%4.4s] %p - [%s] (%4.4X)\n",
/* Abort the parse, no need to examine this method any further */
return (AE_CTRL_TERMINATE);
}
/*******************************************************************************
*
* FUNCTION: AcpiDsMethodError
*
* PARAMETERS: Status - Execution status
* WalkState - Current state
*
* RETURN: Status
*
* DESCRIPTION: Called on method error. Invoke the global exception handler if
* present, dump the method data if the debugger is configured
*
* Note: Allows the exception handler to change the status code
*
******************************************************************************/
{
/* Ignore AE_OK and control exception codes */
if (ACPI_SUCCESS (Status) ||
(Status & AE_CODE_CONTROL))
{
return (Status);
}
/* Invoke the global exception handler */
{
/* Exit the interpreter, allow handler to execute methods */
/*
* Handler can map the exception code to anything it wants, including
* AE_OK, in which case the executing method will not be aborted.
*/
}
if (ACPI_FAILURE (Status))
{
#ifdef ACPI_DEBUGGER
#endif
}
return (Status);
}
/*******************************************************************************
*
* FUNCTION: AcpiDsCreateMethodMutex
*
* PARAMETERS: ObjDesc - The method object
*
* RETURN: Status
*
* DESCRIPTION: Create a mutex object for a serialized control method
*
******************************************************************************/
static ACPI_STATUS
{
/* Create the new mutex object */
if (!MutexDesc)
{
}
/* Create the actual OS Mutex */
if (ACPI_FAILURE (Status))
{
}
}
/*******************************************************************************
*
* FUNCTION: AcpiDsBeginMethodExecution
*
* PARAMETERS: MethodNode - Node of the method
* ObjDesc - The method object
* WalkState - current state, NULL if not yet executing
* a method.
*
* RETURN: Status
*
* DESCRIPTION: Prepare a method for execution. Parses the method if necessary,
* increments the thread count, and waits at the method semaphore
* for clearance to execute.
*
******************************************************************************/
{
if (!MethodNode)
{
}
/* Prevent wraparound of thread count */
{
"Method reached maximum reentrancy limit (255)"));
}
/*
* If this method is serialized, we need to acquire the method mutex.
*/
{
/*
* Create a mutex for the method if it is defined to be Serialized
* and a mutex has not already been created. We defer the mutex creation
* until a method is actually executed, to minimize the object count
*/
{
if (ACPI_FAILURE (Status))
{
}
}
/*
* The CurrentSyncLevel (per-thread) must be less than or equal to
* the sync level of the method. This mechanism provides some
* deadlock prevention.
*
* If the method was auto-serialized, we just ignore the sync level
* mechanism, because auto-serialization of methods can interfere
* with ASL code that actually uses sync levels.
*
* Top-level method invocation has no walk state at this point
*/
if (WalkState &&
{
"Cannot acquire Mutex for method [%4.4s]"
", current SyncLevel is too large (%u)",
}
/*
* Obtain the method mutex if necessary. Do not acquire mutex for a
* recursive call.
*/
if (!WalkState ||
{
/*
* Acquire the method mutex. This releases the interpreter if we
* block (and reacquires it before it returns)
*/
if (ACPI_FAILURE (Status))
{
}
/* Update the mutex and walk info and save the original SyncLevel */
if (WalkState)
{
/*
* Update the current SyncLevel only if this is not an auto-
* serialized method. In the auto case, we have to ignore
* the sync level for the method mutex (created for the
* auto-serialization) because we have no idea of what the
* sync level should be. Therefore, just ignore it.
*/
{
}
}
else
{
}
}
/* Always increase acquisition depth */
}
/*
* Allocate an Owner ID for this method, only if this is the first thread
* to begin concurrent execution. We only need one OwnerId, even if the
* method is invoked recursively.
*/
{
if (ACPI_FAILURE (Status))
{
goto Cleanup;
}
}
/*
* Increment the method parse tree thread count since it has been
* reentered one more time (even if it is the same thread)
*/
/* On error, must release the method mutex (if present) */
{
}
}
/*******************************************************************************
*
* FUNCTION: AcpiDsCallControlMethod
*
* PARAMETERS: Thread - Info for this thread
* ThisWalkState - Current walk state
* Op - Current Op to be walked
*
* RETURN: Status
*
* DESCRIPTION: Transfer execution to a called control method
*
******************************************************************************/
{
UINT32 i;
"Calling method %p, currentstate=%p\n",
/*
* Get the namespace entry for the control method we are about to call
*/
if (!MethodNode)
{
}
if (!ObjDesc)
{
}
/* Init for new method, possibly wait on method mutex */
if (ACPI_FAILURE (Status))
{
}
if (!NextWalkState)
{
goto Cleanup;
}
/*
* The resolved arguments were put on the previous walk state's operand
* stack. Operands on the previous walk state stack always
* start at index 0. Also, null terminate the list of arguments
*/
/*
* Allocate and initialize the evaluation information block
* TBD: this is somewhat inefficient, should change interface to
* DsInitAmlWalk. For now, keeps this struct off the CPU stack
*/
if (!Info)
{
goto Cleanup;
}
if (ACPI_FAILURE (Status))
{
goto Cleanup;
}
/*
* Delete the operands on the previous walkstate operand stack
* (they were copied to new objects)
*/
{
}
/* Clear the operand stack */
ThisWalkState->NumOperands = 0;
"**** Begin nested execution of [%4.4s] **** WalkState=%p\n",
/* Invoke an internal method if necessary */
{
{
}
}
/* On error, we must terminate the method properly */
}
/*******************************************************************************
*
* FUNCTION: AcpiDsRestartControlMethod
*
* PARAMETERS: WalkState - State for preempted method (caller)
* ReturnDesc - Return value from the called method
*
* RETURN: Status
*
* DESCRIPTION: Restart a method that was preempted by another (nested) method
* invocation. Handle the return value (if any) from the callee.
*
******************************************************************************/
{
int SameAsImplicitReturn;
"****Restart [%4.4s] Op %p ReturnValueFromCallee %p\n",
" ReturnFromThisMethodUsed?=%X ResStack %p Walk %p\n",
/* Did the called method return a value? */
if (ReturnDesc)
{
/* Is the implicit return object the same as the return desc? */
/* Are we actually going to use the return value? */
if (WalkState->ReturnUsed)
{
/* Save the return value from the previous method */
if (ACPI_FAILURE (Status))
{
}
/*
* Save as THIS method's return value in case it is returned
* immediately to yet another method
*/
}
/*
* The following code is the optional support for the so-called
* "implicit return". Some AML code assumes that the last value of the
* method is "implicitly" returned to the caller, in the absence of an
* explicit return value.
*
* Just save the last result of the method as the return value.
*
* NOTE: this is optional because the ASL language does not actually
* support this behavior.
*/
{
/*
* Delete the return value if it will not be used by the
* calling method or remove one reference if the explicit return
* is the same as the implicit return value.
*/
}
}
}
/*******************************************************************************
*
* FUNCTION: AcpiDsTerminateControlMethod
*
* PARAMETERS: MethodDesc - Method object
* WalkState - State associated with the method
*
* RETURN: None
*
* DESCRIPTION: Terminate a control method. Delete everything that the method
* created, delete all locals and arguments, and delete the parse
* tree if requested.
*
* MUTEX: Interpreter is locked
*
******************************************************************************/
void
{
/* MethodDesc is required, WalkState is optional */
if (!MethodDesc)
{
}
if (WalkState)
{
/* Delete all arguments and locals */
/*
* If method is serialized, release the mutex and restore the
* current sync level for this thread
*/
{
/* Acquisition Depth handles recursive calls */
{
}
}
/*
* Delete any namespace objects created anywhere within the
* namespace by the execution of this method. Unless:
* 1) This method is a module-level executable code method, in which
* case we want make the objects permanent.
* 2) There are other threads executing the method, in which case we
* will wait until the last thread has completed.
*/
{
/* Delete any direct children of (created by) this method */
/*
* Delete any objects that were created by this method
* elsewhere in the namespace (if any were created).
* Use of the ACPI_METHOD_MODIFIED_NAMESPACE optimizes the
* deletion such that we don't have to perform an entire
* namespace walk for every control method execution.
*/
{
}
}
}
/* Decrement the thread count on the method */
{
}
else
{
"Invalid zero thread count in method"));
}
/* Are there any other threads currently executing this method? */
{
/*
* Additional threads. Do not release the OwnerId in this case,
* we immediately reuse it for the next thread executing this method
*/
"*** Completed execution of one thread, %u threads remaining\n",
}
else
{
/* This is the only executing thread for this method */
/*
* Support to dynamically change a method from NotSerialized to
* Serialized if it appears that the method is incorrectly written and
* does not support multiple thread execution. The best example of this
* is if such a method creates namespace objects and blocks. A second
* thread will fail with an AE_ALREADY_EXISTS exception.
*
* This code is here because we must wait until the last thread exits
* before marking the method as serialized.
*/
{
if (WalkState)
{
ACPI_INFO ((
"Marking method %4.4s as Serialized "
"because of AE_ALREADY_EXISTS error",
}
/*
* Method tried to create an object twice and was marked as
* "pending serialized". The probable cause is that the method
* cannot handle reentrancy.
*
* The method was created as NotSerialized, but it tried to create
* a named object and then blocked, causing the second thread
* entrance to begin and then fail. Workaround this problem by
* marking the method permanently as Serialized when the last
* thread exits here.
*/
}
/* No more threads, we can free the OwnerId */
{
}
}
}