Home | History | Annotate | Line # | Download | only in dispatcher
dsmethod.c revision 1.1.1.2.20.1
      1           1.1  jruoho /******************************************************************************
      2           1.1  jruoho  *
      3           1.1  jruoho  * Module Name: dsmethod - Parser/Interpreter interface - control method parsing
      4           1.1  jruoho  *
      5           1.1  jruoho  *****************************************************************************/
      6           1.1  jruoho 
      7       1.1.1.2  jruoho /*
      8  1.1.1.2.20.1     tls  * Copyright (C) 2000 - 2013, Intel Corp.
      9           1.1  jruoho  * All rights reserved.
     10           1.1  jruoho  *
     11       1.1.1.2  jruoho  * Redistribution and use in source and binary forms, with or without
     12       1.1.1.2  jruoho  * modification, are permitted provided that the following conditions
     13       1.1.1.2  jruoho  * are met:
     14       1.1.1.2  jruoho  * 1. Redistributions of source code must retain the above copyright
     15       1.1.1.2  jruoho  *    notice, this list of conditions, and the following disclaimer,
     16       1.1.1.2  jruoho  *    without modification.
     17       1.1.1.2  jruoho  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
     18       1.1.1.2  jruoho  *    substantially similar to the "NO WARRANTY" disclaimer below
     19       1.1.1.2  jruoho  *    ("Disclaimer") and any redistribution must be conditioned upon
     20       1.1.1.2  jruoho  *    including a substantially similar Disclaimer requirement for further
     21       1.1.1.2  jruoho  *    binary redistribution.
     22       1.1.1.2  jruoho  * 3. Neither the names of the above-listed copyright holders nor the names
     23       1.1.1.2  jruoho  *    of any contributors may be used to endorse or promote products derived
     24       1.1.1.2  jruoho  *    from this software without specific prior written permission.
     25       1.1.1.2  jruoho  *
     26       1.1.1.2  jruoho  * Alternatively, this software may be distributed under the terms of the
     27       1.1.1.2  jruoho  * GNU General Public License ("GPL") version 2 as published by the Free
     28       1.1.1.2  jruoho  * Software Foundation.
     29       1.1.1.2  jruoho  *
     30       1.1.1.2  jruoho  * NO WARRANTY
     31       1.1.1.2  jruoho  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     32       1.1.1.2  jruoho  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     33       1.1.1.2  jruoho  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
     34       1.1.1.2  jruoho  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     35       1.1.1.2  jruoho  * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     36       1.1.1.2  jruoho  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     37       1.1.1.2  jruoho  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     38       1.1.1.2  jruoho  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
     39       1.1.1.2  jruoho  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
     40       1.1.1.2  jruoho  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     41       1.1.1.2  jruoho  * POSSIBILITY OF SUCH DAMAGES.
     42       1.1.1.2  jruoho  */
     43           1.1  jruoho 
     44           1.1  jruoho #define __DSMETHOD_C__
     45           1.1  jruoho 
     46           1.1  jruoho #include "acpi.h"
     47           1.1  jruoho #include "accommon.h"
     48           1.1  jruoho #include "acdispat.h"
     49           1.1  jruoho #include "acinterp.h"
     50           1.1  jruoho #include "acnamesp.h"
     51           1.1  jruoho #include "acdisasm.h"
     52           1.1  jruoho 
     53           1.1  jruoho 
     54           1.1  jruoho #define _COMPONENT          ACPI_DISPATCHER
     55           1.1  jruoho         ACPI_MODULE_NAME    ("dsmethod")
     56           1.1  jruoho 
     57           1.1  jruoho /* Local prototypes */
     58           1.1  jruoho 
     59           1.1  jruoho static ACPI_STATUS
     60           1.1  jruoho AcpiDsCreateMethodMutex (
     61           1.1  jruoho     ACPI_OPERAND_OBJECT     *MethodDesc);
     62           1.1  jruoho 
     63           1.1  jruoho 
     64           1.1  jruoho /*******************************************************************************
     65           1.1  jruoho  *
     66           1.1  jruoho  * FUNCTION:    AcpiDsMethodError
     67           1.1  jruoho  *
     68           1.1  jruoho  * PARAMETERS:  Status          - Execution status
     69           1.1  jruoho  *              WalkState       - Current state
     70           1.1  jruoho  *
     71           1.1  jruoho  * RETURN:      Status
     72           1.1  jruoho  *
     73           1.1  jruoho  * DESCRIPTION: Called on method error. Invoke the global exception handler if
     74           1.1  jruoho  *              present, dump the method data if the disassembler is configured
     75           1.1  jruoho  *
     76           1.1  jruoho  *              Note: Allows the exception handler to change the status code
     77           1.1  jruoho  *
     78           1.1  jruoho  ******************************************************************************/
     79           1.1  jruoho 
     80           1.1  jruoho ACPI_STATUS
     81           1.1  jruoho AcpiDsMethodError (
     82           1.1  jruoho     ACPI_STATUS             Status,
     83           1.1  jruoho     ACPI_WALK_STATE         *WalkState)
     84           1.1  jruoho {
     85           1.1  jruoho     ACPI_FUNCTION_ENTRY ();
     86           1.1  jruoho 
     87           1.1  jruoho 
     88           1.1  jruoho     /* Ignore AE_OK and control exception codes */
     89           1.1  jruoho 
     90           1.1  jruoho     if (ACPI_SUCCESS (Status) ||
     91           1.1  jruoho         (Status & AE_CODE_CONTROL))
     92           1.1  jruoho     {
     93           1.1  jruoho         return (Status);
     94           1.1  jruoho     }
     95           1.1  jruoho 
     96           1.1  jruoho     /* Invoke the global exception handler */
     97           1.1  jruoho 
     98           1.1  jruoho     if (AcpiGbl_ExceptionHandler)
     99           1.1  jruoho     {
    100           1.1  jruoho         /* Exit the interpreter, allow handler to execute methods */
    101           1.1  jruoho 
    102           1.1  jruoho         AcpiExExitInterpreter ();
    103           1.1  jruoho 
    104           1.1  jruoho         /*
    105           1.1  jruoho          * Handler can map the exception code to anything it wants, including
    106           1.1  jruoho          * AE_OK, in which case the executing method will not be aborted.
    107           1.1  jruoho          */
    108           1.1  jruoho         Status = AcpiGbl_ExceptionHandler (Status,
    109           1.1  jruoho                     WalkState->MethodNode ?
    110           1.1  jruoho                         WalkState->MethodNode->Name.Integer : 0,
    111           1.1  jruoho                     WalkState->Opcode, WalkState->AmlOffset, NULL);
    112           1.1  jruoho         AcpiExEnterInterpreter ();
    113           1.1  jruoho     }
    114           1.1  jruoho 
    115           1.1  jruoho     AcpiDsClearImplicitReturn (WalkState);
    116           1.1  jruoho 
    117           1.1  jruoho #ifdef ACPI_DISASSEMBLER
    118           1.1  jruoho     if (ACPI_FAILURE (Status))
    119           1.1  jruoho     {
    120           1.1  jruoho         /* Display method locals/args if disassembler is present */
    121           1.1  jruoho 
    122           1.1  jruoho         AcpiDmDumpMethodInfo (Status, WalkState, WalkState->Op);
    123           1.1  jruoho     }
    124           1.1  jruoho #endif
    125           1.1  jruoho 
    126           1.1  jruoho     return (Status);
    127           1.1  jruoho }
    128           1.1  jruoho 
    129           1.1  jruoho 
    130           1.1  jruoho /*******************************************************************************
    131           1.1  jruoho  *
    132           1.1  jruoho  * FUNCTION:    AcpiDsCreateMethodMutex
    133           1.1  jruoho  *
    134           1.1  jruoho  * PARAMETERS:  ObjDesc             - The method object
    135           1.1  jruoho  *
    136           1.1  jruoho  * RETURN:      Status
    137           1.1  jruoho  *
    138           1.1  jruoho  * DESCRIPTION: Create a mutex object for a serialized control method
    139           1.1  jruoho  *
    140           1.1  jruoho  ******************************************************************************/
    141           1.1  jruoho 
    142           1.1  jruoho static ACPI_STATUS
    143           1.1  jruoho AcpiDsCreateMethodMutex (
    144           1.1  jruoho     ACPI_OPERAND_OBJECT     *MethodDesc)
    145           1.1  jruoho {
    146           1.1  jruoho     ACPI_OPERAND_OBJECT     *MutexDesc;
    147           1.1  jruoho     ACPI_STATUS             Status;
    148           1.1  jruoho 
    149           1.1  jruoho 
    150           1.1  jruoho     ACPI_FUNCTION_TRACE (DsCreateMethodMutex);
    151           1.1  jruoho 
    152           1.1  jruoho 
    153           1.1  jruoho     /* Create the new mutex object */
    154           1.1  jruoho 
    155           1.1  jruoho     MutexDesc = AcpiUtCreateInternalObject (ACPI_TYPE_MUTEX);
    156           1.1  jruoho     if (!MutexDesc)
    157           1.1  jruoho     {
    158           1.1  jruoho         return_ACPI_STATUS (AE_NO_MEMORY);
    159           1.1  jruoho     }
    160           1.1  jruoho 
    161           1.1  jruoho     /* Create the actual OS Mutex */
    162           1.1  jruoho 
    163           1.1  jruoho     Status = AcpiOsCreateMutex (&MutexDesc->Mutex.OsMutex);
    164           1.1  jruoho     if (ACPI_FAILURE (Status))
    165           1.1  jruoho     {
    166  1.1.1.2.20.1     tls         AcpiUtDeleteObjectDesc (MutexDesc);
    167           1.1  jruoho         return_ACPI_STATUS (Status);
    168           1.1  jruoho     }
    169           1.1  jruoho 
    170           1.1  jruoho     MutexDesc->Mutex.SyncLevel = MethodDesc->Method.SyncLevel;
    171           1.1  jruoho     MethodDesc->Method.Mutex = MutexDesc;
    172           1.1  jruoho     return_ACPI_STATUS (AE_OK);
    173           1.1  jruoho }
    174           1.1  jruoho 
    175           1.1  jruoho 
    176           1.1  jruoho /*******************************************************************************
    177           1.1  jruoho  *
    178           1.1  jruoho  * FUNCTION:    AcpiDsBeginMethodExecution
    179           1.1  jruoho  *
    180           1.1  jruoho  * PARAMETERS:  MethodNode          - Node of the method
    181           1.1  jruoho  *              ObjDesc             - The method object
    182           1.1  jruoho  *              WalkState           - current state, NULL if not yet executing
    183           1.1  jruoho  *                                    a method.
    184           1.1  jruoho  *
    185           1.1  jruoho  * RETURN:      Status
    186           1.1  jruoho  *
    187  1.1.1.2.20.1     tls  * DESCRIPTION: Prepare a method for execution. Parses the method if necessary,
    188           1.1  jruoho  *              increments the thread count, and waits at the method semaphore
    189           1.1  jruoho  *              for clearance to execute.
    190           1.1  jruoho  *
    191           1.1  jruoho  ******************************************************************************/
    192           1.1  jruoho 
    193           1.1  jruoho ACPI_STATUS
    194           1.1  jruoho AcpiDsBeginMethodExecution (
    195           1.1  jruoho     ACPI_NAMESPACE_NODE     *MethodNode,
    196           1.1  jruoho     ACPI_OPERAND_OBJECT     *ObjDesc,
    197           1.1  jruoho     ACPI_WALK_STATE         *WalkState)
    198           1.1  jruoho {
    199           1.1  jruoho     ACPI_STATUS             Status = AE_OK;
    200           1.1  jruoho 
    201           1.1  jruoho 
    202           1.1  jruoho     ACPI_FUNCTION_TRACE_PTR (DsBeginMethodExecution, MethodNode);
    203           1.1  jruoho 
    204           1.1  jruoho 
    205           1.1  jruoho     if (!MethodNode)
    206           1.1  jruoho     {
    207           1.1  jruoho         return_ACPI_STATUS (AE_NULL_ENTRY);
    208           1.1  jruoho     }
    209           1.1  jruoho 
    210           1.1  jruoho     /* Prevent wraparound of thread count */
    211           1.1  jruoho 
    212           1.1  jruoho     if (ObjDesc->Method.ThreadCount == ACPI_UINT8_MAX)
    213           1.1  jruoho     {
    214           1.1  jruoho         ACPI_ERROR ((AE_INFO,
    215           1.1  jruoho             "Method reached maximum reentrancy limit (255)"));
    216           1.1  jruoho         return_ACPI_STATUS (AE_AML_METHOD_LIMIT);
    217           1.1  jruoho     }
    218           1.1  jruoho 
    219           1.1  jruoho     /*
    220           1.1  jruoho      * If this method is serialized, we need to acquire the method mutex.
    221           1.1  jruoho      */
    222       1.1.1.2  jruoho     if (ObjDesc->Method.InfoFlags & ACPI_METHOD_SERIALIZED)
    223           1.1  jruoho     {
    224           1.1  jruoho         /*
    225           1.1  jruoho          * Create a mutex for the method if it is defined to be Serialized
    226           1.1  jruoho          * and a mutex has not already been created. We defer the mutex creation
    227           1.1  jruoho          * until a method is actually executed, to minimize the object count
    228           1.1  jruoho          */
    229           1.1  jruoho         if (!ObjDesc->Method.Mutex)
    230           1.1  jruoho         {
    231           1.1  jruoho             Status = AcpiDsCreateMethodMutex (ObjDesc);
    232           1.1  jruoho             if (ACPI_FAILURE (Status))
    233           1.1  jruoho             {
    234           1.1  jruoho                 return_ACPI_STATUS (Status);
    235           1.1  jruoho             }
    236           1.1  jruoho         }
    237           1.1  jruoho 
    238           1.1  jruoho         /*
    239           1.1  jruoho          * The CurrentSyncLevel (per-thread) must be less than or equal to
    240           1.1  jruoho          * the sync level of the method. This mechanism provides some
    241           1.1  jruoho          * deadlock prevention
    242           1.1  jruoho          *
    243           1.1  jruoho          * Top-level method invocation has no walk state at this point
    244           1.1  jruoho          */
    245           1.1  jruoho         if (WalkState &&
    246           1.1  jruoho             (WalkState->Thread->CurrentSyncLevel > ObjDesc->Method.Mutex->Mutex.SyncLevel))
    247           1.1  jruoho         {
    248           1.1  jruoho             ACPI_ERROR ((AE_INFO,
    249           1.1  jruoho                 "Cannot acquire Mutex for method [%4.4s], current SyncLevel is too large (%u)",
    250           1.1  jruoho                 AcpiUtGetNodeName (MethodNode),
    251           1.1  jruoho                 WalkState->Thread->CurrentSyncLevel));
    252           1.1  jruoho 
    253           1.1  jruoho             return_ACPI_STATUS (AE_AML_MUTEX_ORDER);
    254           1.1  jruoho         }
    255           1.1  jruoho 
    256           1.1  jruoho         /*
    257           1.1  jruoho          * Obtain the method mutex if necessary. Do not acquire mutex for a
    258           1.1  jruoho          * recursive call.
    259           1.1  jruoho          */
    260           1.1  jruoho         if (!WalkState ||
    261           1.1  jruoho             !ObjDesc->Method.Mutex->Mutex.ThreadId ||
    262           1.1  jruoho             (WalkState->Thread->ThreadId != ObjDesc->Method.Mutex->Mutex.ThreadId))
    263           1.1  jruoho         {
    264           1.1  jruoho             /*
    265           1.1  jruoho              * Acquire the method mutex. This releases the interpreter if we
    266           1.1  jruoho              * block (and reacquires it before it returns)
    267           1.1  jruoho              */
    268           1.1  jruoho             Status = AcpiExSystemWaitMutex (ObjDesc->Method.Mutex->Mutex.OsMutex,
    269           1.1  jruoho                         ACPI_WAIT_FOREVER);
    270           1.1  jruoho             if (ACPI_FAILURE (Status))
    271           1.1  jruoho             {
    272           1.1  jruoho                 return_ACPI_STATUS (Status);
    273           1.1  jruoho             }
    274           1.1  jruoho 
    275           1.1  jruoho             /* Update the mutex and walk info and save the original SyncLevel */
    276           1.1  jruoho 
    277           1.1  jruoho             if (WalkState)
    278           1.1  jruoho             {
    279           1.1  jruoho                 ObjDesc->Method.Mutex->Mutex.OriginalSyncLevel =
    280           1.1  jruoho                     WalkState->Thread->CurrentSyncLevel;
    281           1.1  jruoho 
    282           1.1  jruoho                 ObjDesc->Method.Mutex->Mutex.ThreadId = WalkState->Thread->ThreadId;
    283           1.1  jruoho                 WalkState->Thread->CurrentSyncLevel = ObjDesc->Method.SyncLevel;
    284           1.1  jruoho             }
    285           1.1  jruoho             else
    286           1.1  jruoho             {
    287           1.1  jruoho                 ObjDesc->Method.Mutex->Mutex.OriginalSyncLevel =
    288           1.1  jruoho                     ObjDesc->Method.Mutex->Mutex.SyncLevel;
    289           1.1  jruoho             }
    290           1.1  jruoho         }
    291           1.1  jruoho 
    292           1.1  jruoho         /* Always increase acquisition depth */
    293           1.1  jruoho 
    294           1.1  jruoho         ObjDesc->Method.Mutex->Mutex.AcquisitionDepth++;
    295           1.1  jruoho     }
    296           1.1  jruoho 
    297           1.1  jruoho     /*
    298           1.1  jruoho      * Allocate an Owner ID for this method, only if this is the first thread
    299           1.1  jruoho      * to begin concurrent execution. We only need one OwnerId, even if the
    300           1.1  jruoho      * method is invoked recursively.
    301           1.1  jruoho      */
    302           1.1  jruoho     if (!ObjDesc->Method.OwnerId)
    303           1.1  jruoho     {
    304           1.1  jruoho         Status = AcpiUtAllocateOwnerId (&ObjDesc->Method.OwnerId);
    305           1.1  jruoho         if (ACPI_FAILURE (Status))
    306           1.1  jruoho         {
    307           1.1  jruoho             goto Cleanup;
    308           1.1  jruoho         }
    309           1.1  jruoho     }
    310           1.1  jruoho 
    311           1.1  jruoho     /*
    312           1.1  jruoho      * Increment the method parse tree thread count since it has been
    313           1.1  jruoho      * reentered one more time (even if it is the same thread)
    314           1.1  jruoho      */
    315           1.1  jruoho     ObjDesc->Method.ThreadCount++;
    316           1.1  jruoho     AcpiMethodCount++;
    317           1.1  jruoho     return_ACPI_STATUS (Status);
    318           1.1  jruoho 
    319           1.1  jruoho 
    320           1.1  jruoho Cleanup:
    321           1.1  jruoho     /* On error, must release the method mutex (if present) */
    322           1.1  jruoho 
    323           1.1  jruoho     if (ObjDesc->Method.Mutex)
    324           1.1  jruoho     {
    325           1.1  jruoho         AcpiOsReleaseMutex (ObjDesc->Method.Mutex->Mutex.OsMutex);
    326           1.1  jruoho     }
    327           1.1  jruoho     return_ACPI_STATUS (Status);
    328           1.1  jruoho }
    329           1.1  jruoho 
    330           1.1  jruoho 
    331           1.1  jruoho /*******************************************************************************
    332           1.1  jruoho  *
    333           1.1  jruoho  * FUNCTION:    AcpiDsCallControlMethod
    334           1.1  jruoho  *
    335           1.1  jruoho  * PARAMETERS:  Thread              - Info for this thread
    336           1.1  jruoho  *              ThisWalkState       - Current walk state
    337           1.1  jruoho  *              Op                  - Current Op to be walked
    338           1.1  jruoho  *
    339           1.1  jruoho  * RETURN:      Status
    340           1.1  jruoho  *
    341           1.1  jruoho  * DESCRIPTION: Transfer execution to a called control method
    342           1.1  jruoho  *
    343           1.1  jruoho  ******************************************************************************/
    344           1.1  jruoho 
    345           1.1  jruoho ACPI_STATUS
    346           1.1  jruoho AcpiDsCallControlMethod (
    347           1.1  jruoho     ACPI_THREAD_STATE       *Thread,
    348           1.1  jruoho     ACPI_WALK_STATE         *ThisWalkState,
    349           1.1  jruoho     ACPI_PARSE_OBJECT       *Op)
    350           1.1  jruoho {
    351           1.1  jruoho     ACPI_STATUS             Status;
    352           1.1  jruoho     ACPI_NAMESPACE_NODE     *MethodNode;
    353           1.1  jruoho     ACPI_WALK_STATE         *NextWalkState = NULL;
    354           1.1  jruoho     ACPI_OPERAND_OBJECT     *ObjDesc;
    355           1.1  jruoho     ACPI_EVALUATE_INFO      *Info;
    356           1.1  jruoho     UINT32                  i;
    357           1.1  jruoho 
    358           1.1  jruoho 
    359           1.1  jruoho     ACPI_FUNCTION_TRACE_PTR (DsCallControlMethod, ThisWalkState);
    360           1.1  jruoho 
    361           1.1  jruoho     ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "Calling method %p, currentstate=%p\n",
    362           1.1  jruoho         ThisWalkState->PrevOp, ThisWalkState));
    363           1.1  jruoho 
    364           1.1  jruoho     /*
    365           1.1  jruoho      * Get the namespace entry for the control method we are about to call
    366           1.1  jruoho      */
    367           1.1  jruoho     MethodNode = ThisWalkState->MethodCallNode;
    368           1.1  jruoho     if (!MethodNode)
    369           1.1  jruoho     {
    370           1.1  jruoho         return_ACPI_STATUS (AE_NULL_ENTRY);
    371           1.1  jruoho     }
    372           1.1  jruoho 
    373           1.1  jruoho     ObjDesc = AcpiNsGetAttachedObject (MethodNode);
    374           1.1  jruoho     if (!ObjDesc)
    375           1.1  jruoho     {
    376           1.1  jruoho         return_ACPI_STATUS (AE_NULL_OBJECT);
    377           1.1  jruoho     }
    378           1.1  jruoho 
    379           1.1  jruoho     /* Init for new method, possibly wait on method mutex */
    380           1.1  jruoho 
    381           1.1  jruoho     Status = AcpiDsBeginMethodExecution (MethodNode, ObjDesc,
    382           1.1  jruoho                 ThisWalkState);
    383           1.1  jruoho     if (ACPI_FAILURE (Status))
    384           1.1  jruoho     {
    385           1.1  jruoho         return_ACPI_STATUS (Status);
    386           1.1  jruoho     }
    387           1.1  jruoho 
    388           1.1  jruoho     /* Begin method parse/execution. Create a new walk state */
    389           1.1  jruoho 
    390           1.1  jruoho     NextWalkState = AcpiDsCreateWalkState (ObjDesc->Method.OwnerId,
    391           1.1  jruoho                         NULL, ObjDesc, Thread);
    392           1.1  jruoho     if (!NextWalkState)
    393           1.1  jruoho     {
    394           1.1  jruoho         Status = AE_NO_MEMORY;
    395           1.1  jruoho         goto Cleanup;
    396           1.1  jruoho     }
    397           1.1  jruoho 
    398           1.1  jruoho     /*
    399           1.1  jruoho      * The resolved arguments were put on the previous walk state's operand
    400           1.1  jruoho      * stack. Operands on the previous walk state stack always
    401           1.1  jruoho      * start at index 0. Also, null terminate the list of arguments
    402           1.1  jruoho      */
    403           1.1  jruoho     ThisWalkState->Operands [ThisWalkState->NumOperands] = NULL;
    404           1.1  jruoho 
    405           1.1  jruoho     /*
    406           1.1  jruoho      * Allocate and initialize the evaluation information block
    407           1.1  jruoho      * TBD: this is somewhat inefficient, should change interface to
    408           1.1  jruoho      * DsInitAmlWalk. For now, keeps this struct off the CPU stack
    409           1.1  jruoho      */
    410           1.1  jruoho     Info = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_EVALUATE_INFO));
    411           1.1  jruoho     if (!Info)
    412           1.1  jruoho     {
    413  1.1.1.2.20.1     tls         Status = AE_NO_MEMORY;
    414  1.1.1.2.20.1     tls         goto Cleanup;
    415           1.1  jruoho     }
    416           1.1  jruoho 
    417           1.1  jruoho     Info->Parameters = &ThisWalkState->Operands[0];
    418           1.1  jruoho 
    419           1.1  jruoho     Status = AcpiDsInitAmlWalk (NextWalkState, NULL, MethodNode,
    420           1.1  jruoho                 ObjDesc->Method.AmlStart, ObjDesc->Method.AmlLength,
    421           1.1  jruoho                 Info, ACPI_IMODE_EXECUTE);
    422           1.1  jruoho 
    423           1.1  jruoho     ACPI_FREE (Info);
    424           1.1  jruoho     if (ACPI_FAILURE (Status))
    425           1.1  jruoho     {
    426           1.1  jruoho         goto Cleanup;
    427           1.1  jruoho     }
    428           1.1  jruoho 
    429           1.1  jruoho     /*
    430           1.1  jruoho      * Delete the operands on the previous walkstate operand stack
    431           1.1  jruoho      * (they were copied to new objects)
    432           1.1  jruoho      */
    433           1.1  jruoho     for (i = 0; i < ObjDesc->Method.ParamCount; i++)
    434           1.1  jruoho     {
    435           1.1  jruoho         AcpiUtRemoveReference (ThisWalkState->Operands [i]);
    436           1.1  jruoho         ThisWalkState->Operands [i] = NULL;
    437           1.1  jruoho     }
    438           1.1  jruoho 
    439           1.1  jruoho     /* Clear the operand stack */
    440           1.1  jruoho 
    441           1.1  jruoho     ThisWalkState->NumOperands = 0;
    442           1.1  jruoho 
    443           1.1  jruoho     ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
    444           1.1  jruoho         "**** Begin nested execution of [%4.4s] **** WalkState=%p\n",
    445           1.1  jruoho         MethodNode->Name.Ascii, NextWalkState));
    446           1.1  jruoho 
    447           1.1  jruoho     /* Invoke an internal method if necessary */
    448           1.1  jruoho 
    449       1.1.1.2  jruoho     if (ObjDesc->Method.InfoFlags & ACPI_METHOD_INTERNAL_ONLY)
    450           1.1  jruoho     {
    451       1.1.1.2  jruoho         Status = ObjDesc->Method.Dispatch.Implementation (NextWalkState);
    452           1.1  jruoho         if (Status == AE_OK)
    453           1.1  jruoho         {
    454           1.1  jruoho             Status = AE_CTRL_TERMINATE;
    455           1.1  jruoho         }
    456           1.1  jruoho     }
    457           1.1  jruoho 
    458           1.1  jruoho     return_ACPI_STATUS (Status);
    459           1.1  jruoho 
    460           1.1  jruoho 
    461           1.1  jruoho Cleanup:
    462           1.1  jruoho 
    463           1.1  jruoho     /* On error, we must terminate the method properly */
    464           1.1  jruoho 
    465           1.1  jruoho     AcpiDsTerminateControlMethod (ObjDesc, NextWalkState);
    466           1.1  jruoho     if (NextWalkState)
    467           1.1  jruoho     {
    468           1.1  jruoho         AcpiDsDeleteWalkState (NextWalkState);
    469           1.1  jruoho     }
    470           1.1  jruoho 
    471           1.1  jruoho     return_ACPI_STATUS (Status);
    472           1.1  jruoho }
    473           1.1  jruoho 
    474           1.1  jruoho 
    475           1.1  jruoho /*******************************************************************************
    476           1.1  jruoho  *
    477           1.1  jruoho  * FUNCTION:    AcpiDsRestartControlMethod
    478           1.1  jruoho  *
    479           1.1  jruoho  * PARAMETERS:  WalkState           - State for preempted method (caller)
    480           1.1  jruoho  *              ReturnDesc          - Return value from the called method
    481           1.1  jruoho  *
    482           1.1  jruoho  * RETURN:      Status
    483           1.1  jruoho  *
    484           1.1  jruoho  * DESCRIPTION: Restart a method that was preempted by another (nested) method
    485  1.1.1.2.20.1     tls  *              invocation. Handle the return value (if any) from the callee.
    486           1.1  jruoho  *
    487           1.1  jruoho  ******************************************************************************/
    488           1.1  jruoho 
    489           1.1  jruoho ACPI_STATUS
    490           1.1  jruoho AcpiDsRestartControlMethod (
    491           1.1  jruoho     ACPI_WALK_STATE         *WalkState,
    492           1.1  jruoho     ACPI_OPERAND_OBJECT     *ReturnDesc)
    493           1.1  jruoho {
    494           1.1  jruoho     ACPI_STATUS             Status;
    495           1.1  jruoho     int                     SameAsImplicitReturn;
    496           1.1  jruoho 
    497           1.1  jruoho 
    498           1.1  jruoho     ACPI_FUNCTION_TRACE_PTR (DsRestartControlMethod, WalkState);
    499           1.1  jruoho 
    500           1.1  jruoho 
    501           1.1  jruoho     ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
    502           1.1  jruoho         "****Restart [%4.4s] Op %p ReturnValueFromCallee %p\n",
    503           1.1  jruoho         AcpiUtGetNodeName (WalkState->MethodNode),
    504           1.1  jruoho         WalkState->MethodCallOp, ReturnDesc));
    505           1.1  jruoho 
    506           1.1  jruoho     ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
    507           1.1  jruoho         "    ReturnFromThisMethodUsed?=%X ResStack %p Walk %p\n",
    508           1.1  jruoho         WalkState->ReturnUsed,
    509           1.1  jruoho         WalkState->Results, WalkState));
    510           1.1  jruoho 
    511           1.1  jruoho     /* Did the called method return a value? */
    512           1.1  jruoho 
    513           1.1  jruoho     if (ReturnDesc)
    514           1.1  jruoho     {
    515           1.1  jruoho         /* Is the implicit return object the same as the return desc? */
    516           1.1  jruoho 
    517           1.1  jruoho         SameAsImplicitReturn = (WalkState->ImplicitReturnObj == ReturnDesc);
    518           1.1  jruoho 
    519           1.1  jruoho         /* Are we actually going to use the return value? */
    520           1.1  jruoho 
    521           1.1  jruoho         if (WalkState->ReturnUsed)
    522           1.1  jruoho         {
    523           1.1  jruoho             /* Save the return value from the previous method */
    524           1.1  jruoho 
    525           1.1  jruoho             Status = AcpiDsResultPush (ReturnDesc, WalkState);
    526           1.1  jruoho             if (ACPI_FAILURE (Status))
    527           1.1  jruoho             {
    528           1.1  jruoho                 AcpiUtRemoveReference (ReturnDesc);
    529           1.1  jruoho                 return_ACPI_STATUS (Status);
    530           1.1  jruoho             }
    531           1.1  jruoho 
    532           1.1  jruoho             /*
    533           1.1  jruoho              * Save as THIS method's return value in case it is returned
    534           1.1  jruoho              * immediately to yet another method
    535           1.1  jruoho              */
    536           1.1  jruoho             WalkState->ReturnDesc = ReturnDesc;
    537           1.1  jruoho         }
    538           1.1  jruoho 
    539           1.1  jruoho         /*
    540           1.1  jruoho          * The following code is the optional support for the so-called
    541           1.1  jruoho          * "implicit return". Some AML code assumes that the last value of the
    542           1.1  jruoho          * method is "implicitly" returned to the caller, in the absence of an
    543           1.1  jruoho          * explicit return value.
    544           1.1  jruoho          *
    545           1.1  jruoho          * Just save the last result of the method as the return value.
    546           1.1  jruoho          *
    547           1.1  jruoho          * NOTE: this is optional because the ASL language does not actually
    548           1.1  jruoho          * support this behavior.
    549           1.1  jruoho          */
    550           1.1  jruoho         else if (!AcpiDsDoImplicitReturn (ReturnDesc, WalkState, FALSE) ||
    551           1.1  jruoho                  SameAsImplicitReturn)
    552           1.1  jruoho         {
    553           1.1  jruoho             /*
    554           1.1  jruoho              * Delete the return value if it will not be used by the
    555           1.1  jruoho              * calling method or remove one reference if the explicit return
    556           1.1  jruoho              * is the same as the implicit return value.
    557           1.1  jruoho              */
    558           1.1  jruoho             AcpiUtRemoveReference (ReturnDesc);
    559           1.1  jruoho         }
    560           1.1  jruoho     }
    561           1.1  jruoho 
    562           1.1  jruoho     return_ACPI_STATUS (AE_OK);
    563           1.1  jruoho }
    564           1.1  jruoho 
    565           1.1  jruoho 
    566           1.1  jruoho /*******************************************************************************
    567           1.1  jruoho  *
    568           1.1  jruoho  * FUNCTION:    AcpiDsTerminateControlMethod
    569           1.1  jruoho  *
    570           1.1  jruoho  * PARAMETERS:  MethodDesc          - Method object
    571           1.1  jruoho  *              WalkState           - State associated with the method
    572           1.1  jruoho  *
    573           1.1  jruoho  * RETURN:      None
    574           1.1  jruoho  *
    575  1.1.1.2.20.1     tls  * DESCRIPTION: Terminate a control method. Delete everything that the method
    576           1.1  jruoho  *              created, delete all locals and arguments, and delete the parse
    577           1.1  jruoho  *              tree if requested.
    578           1.1  jruoho  *
    579           1.1  jruoho  * MUTEX:       Interpreter is locked
    580           1.1  jruoho  *
    581           1.1  jruoho  ******************************************************************************/
    582           1.1  jruoho 
    583           1.1  jruoho void
    584           1.1  jruoho AcpiDsTerminateControlMethod (
    585           1.1  jruoho     ACPI_OPERAND_OBJECT     *MethodDesc,
    586           1.1  jruoho     ACPI_WALK_STATE         *WalkState)
    587           1.1  jruoho {
    588           1.1  jruoho 
    589           1.1  jruoho     ACPI_FUNCTION_TRACE_PTR (DsTerminateControlMethod, WalkState);
    590           1.1  jruoho 
    591           1.1  jruoho 
    592           1.1  jruoho     /* MethodDesc is required, WalkState is optional */
    593           1.1  jruoho 
    594           1.1  jruoho     if (!MethodDesc)
    595           1.1  jruoho     {
    596           1.1  jruoho         return_VOID;
    597           1.1  jruoho     }
    598           1.1  jruoho 
    599           1.1  jruoho     if (WalkState)
    600           1.1  jruoho     {
    601           1.1  jruoho         /* Delete all arguments and locals */
    602           1.1  jruoho 
    603           1.1  jruoho         AcpiDsMethodDataDeleteAll (WalkState);
    604           1.1  jruoho 
    605           1.1  jruoho         /*
    606           1.1  jruoho          * If method is serialized, release the mutex and restore the
    607           1.1  jruoho          * current sync level for this thread
    608           1.1  jruoho          */
    609           1.1  jruoho         if (MethodDesc->Method.Mutex)
    610           1.1  jruoho         {
    611           1.1  jruoho             /* Acquisition Depth handles recursive calls */
    612           1.1  jruoho 
    613           1.1  jruoho             MethodDesc->Method.Mutex->Mutex.AcquisitionDepth--;
    614           1.1  jruoho             if (!MethodDesc->Method.Mutex->Mutex.AcquisitionDepth)
    615           1.1  jruoho             {
    616           1.1  jruoho                 WalkState->Thread->CurrentSyncLevel =
    617           1.1  jruoho                     MethodDesc->Method.Mutex->Mutex.OriginalSyncLevel;
    618           1.1  jruoho 
    619           1.1  jruoho                 AcpiOsReleaseMutex (MethodDesc->Method.Mutex->Mutex.OsMutex);
    620           1.1  jruoho                 MethodDesc->Method.Mutex->Mutex.ThreadId = 0;
    621           1.1  jruoho             }
    622           1.1  jruoho         }
    623           1.1  jruoho 
    624           1.1  jruoho         /*
    625           1.1  jruoho          * Delete any namespace objects created anywhere within the
    626       1.1.1.2  jruoho          * namespace by the execution of this method. Unless:
    627       1.1.1.2  jruoho          * 1) This method is a module-level executable code method, in which
    628       1.1.1.2  jruoho          *    case we want make the objects permanent.
    629       1.1.1.2  jruoho          * 2) There are other threads executing the method, in which case we
    630       1.1.1.2  jruoho          *    will wait until the last thread has completed.
    631           1.1  jruoho          */
    632       1.1.1.2  jruoho         if (!(MethodDesc->Method.InfoFlags & ACPI_METHOD_MODULE_LEVEL) &&
    633       1.1.1.2  jruoho              (MethodDesc->Method.ThreadCount == 1))
    634           1.1  jruoho         {
    635           1.1  jruoho             /* Delete any direct children of (created by) this method */
    636           1.1  jruoho 
    637           1.1  jruoho             AcpiNsDeleteNamespaceSubtree (WalkState->MethodNode);
    638           1.1  jruoho 
    639           1.1  jruoho             /*
    640           1.1  jruoho              * Delete any objects that were created by this method
    641           1.1  jruoho              * elsewhere in the namespace (if any were created).
    642       1.1.1.2  jruoho              * Use of the ACPI_METHOD_MODIFIED_NAMESPACE optimizes the
    643       1.1.1.2  jruoho              * deletion such that we don't have to perform an entire
    644       1.1.1.2  jruoho              * namespace walk for every control method execution.
    645           1.1  jruoho              */
    646       1.1.1.2  jruoho             if (MethodDesc->Method.InfoFlags & ACPI_METHOD_MODIFIED_NAMESPACE)
    647           1.1  jruoho             {
    648           1.1  jruoho                 AcpiNsDeleteNamespaceByOwner (MethodDesc->Method.OwnerId);
    649       1.1.1.2  jruoho                 MethodDesc->Method.InfoFlags &= ~ACPI_METHOD_MODIFIED_NAMESPACE;
    650           1.1  jruoho             }
    651           1.1  jruoho         }
    652           1.1  jruoho     }
    653           1.1  jruoho 
    654           1.1  jruoho     /* Decrement the thread count on the method */
    655           1.1  jruoho 
    656           1.1  jruoho     if (MethodDesc->Method.ThreadCount)
    657           1.1  jruoho     {
    658           1.1  jruoho         MethodDesc->Method.ThreadCount--;
    659           1.1  jruoho     }
    660           1.1  jruoho     else
    661           1.1  jruoho     {
    662           1.1  jruoho         ACPI_ERROR ((AE_INFO,
    663           1.1  jruoho             "Invalid zero thread count in method"));
    664           1.1  jruoho     }
    665           1.1  jruoho 
    666           1.1  jruoho     /* Are there any other threads currently executing this method? */
    667           1.1  jruoho 
    668           1.1  jruoho     if (MethodDesc->Method.ThreadCount)
    669           1.1  jruoho     {
    670           1.1  jruoho         /*
    671           1.1  jruoho          * Additional threads. Do not release the OwnerId in this case,
    672           1.1  jruoho          * we immediately reuse it for the next thread executing this method
    673           1.1  jruoho          */
    674           1.1  jruoho         ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
    675           1.1  jruoho             "*** Completed execution of one thread, %u threads remaining\n",
    676           1.1  jruoho             MethodDesc->Method.ThreadCount));
    677           1.1  jruoho     }
    678           1.1  jruoho     else
    679           1.1  jruoho     {
    680           1.1  jruoho         /* This is the only executing thread for this method */
    681           1.1  jruoho 
    682           1.1  jruoho         /*
    683           1.1  jruoho          * Support to dynamically change a method from NotSerialized to
    684           1.1  jruoho          * Serialized if it appears that the method is incorrectly written and
    685           1.1  jruoho          * does not support multiple thread execution. The best example of this
    686           1.1  jruoho          * is if such a method creates namespace objects and blocks. A second
    687       1.1.1.2  jruoho          * thread will fail with an AE_ALREADY_EXISTS exception.
    688           1.1  jruoho          *
    689           1.1  jruoho          * This code is here because we must wait until the last thread exits
    690       1.1.1.2  jruoho          * before marking the method as serialized.
    691           1.1  jruoho          */
    692       1.1.1.2  jruoho         if (MethodDesc->Method.InfoFlags & ACPI_METHOD_SERIALIZED_PENDING)
    693           1.1  jruoho         {
    694       1.1.1.2  jruoho             if (WalkState)
    695       1.1.1.2  jruoho             {
    696       1.1.1.2  jruoho                 ACPI_INFO ((AE_INFO,
    697       1.1.1.2  jruoho                     "Marking method %4.4s as Serialized because of AE_ALREADY_EXISTS error",
    698       1.1.1.2  jruoho                     WalkState->MethodNode->Name.Ascii));
    699       1.1.1.2  jruoho             }
    700       1.1.1.2  jruoho 
    701       1.1.1.2  jruoho             /*
    702       1.1.1.2  jruoho              * Method tried to create an object twice and was marked as
    703       1.1.1.2  jruoho              * "pending serialized". The probable cause is that the method
    704       1.1.1.2  jruoho              * cannot handle reentrancy.
    705       1.1.1.2  jruoho              *
    706       1.1.1.2  jruoho              * The method was created as NotSerialized, but it tried to create
    707       1.1.1.2  jruoho              * a named object and then blocked, causing the second thread
    708       1.1.1.2  jruoho              * entrance to begin and then fail. Workaround this problem by
    709       1.1.1.2  jruoho              * marking the method permanently as Serialized when the last
    710       1.1.1.2  jruoho              * thread exits here.
    711       1.1.1.2  jruoho              */
    712       1.1.1.2  jruoho             MethodDesc->Method.InfoFlags &= ~ACPI_METHOD_SERIALIZED_PENDING;
    713       1.1.1.2  jruoho             MethodDesc->Method.InfoFlags |= ACPI_METHOD_SERIALIZED;
    714       1.1.1.2  jruoho             MethodDesc->Method.SyncLevel = 0;
    715           1.1  jruoho         }
    716           1.1  jruoho 
    717           1.1  jruoho         /* No more threads, we can free the OwnerId */
    718           1.1  jruoho 
    719       1.1.1.2  jruoho         if (!(MethodDesc->Method.InfoFlags & ACPI_METHOD_MODULE_LEVEL))
    720           1.1  jruoho         {
    721           1.1  jruoho             AcpiUtReleaseOwnerId (&MethodDesc->Method.OwnerId);
    722           1.1  jruoho         }
    723           1.1  jruoho     }
    724           1.1  jruoho 
    725           1.1  jruoho     return_VOID;
    726           1.1  jruoho }
    727