Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:24:02

0001 /******************************************************************************
0002  *
0003  * Module Name: dsmethod - Parser/Interpreter interface - control method parsing
0004  *
0005  *****************************************************************************/
0006 
0007 /******************************************************************************
0008  *
0009  * 1. Copyright Notice
0010  *
0011  * Some or all of this work - Copyright (c) 1999 - 2024, Intel Corp.
0012  * All rights reserved.
0013  *
0014  * 2. License
0015  *
0016  * 2.1. This is your license from Intel Corp. under its intellectual property
0017  * rights. You may have additional license terms from the party that provided
0018  * you this software, covering your right to use that party's intellectual
0019  * property rights.
0020  *
0021  * 2.2. Intel grants, free of charge, to any person ("Licensee") obtaining a
0022  * copy of the source code appearing in this file ("Covered Code") an
0023  * irrevocable, perpetual, worldwide license under Intel's copyrights in the
0024  * base code distributed originally by Intel ("Original Intel Code") to copy,
0025  * make derivatives, distribute, use and display any portion of the Covered
0026  * Code in any form, with the right to sublicense such rights; and
0027  *
0028  * 2.3. Intel grants Licensee a non-exclusive and non-transferable patent
0029  * license (with the right to sublicense), under only those claims of Intel
0030  * patents that are infringed by the Original Intel Code, to make, use, sell,
0031  * offer to sell, and import the Covered Code and derivative works thereof
0032  * solely to the minimum extent necessary to exercise the above copyright
0033  * license, and in no event shall the patent license extend to any additions
0034  * to or modifications of the Original Intel Code. No other license or right
0035  * is granted directly or by implication, estoppel or otherwise;
0036  *
0037  * The above copyright and patent license is granted only if the following
0038  * conditions are met:
0039  *
0040  * 3. Conditions
0041  *
0042  * 3.1. Redistribution of Source with Rights to Further Distribute Source.
0043  * Redistribution of source code of any substantial portion of the Covered
0044  * Code or modification with rights to further distribute source must include
0045  * the above Copyright Notice, the above License, this list of Conditions,
0046  * and the following Disclaimer and Export Compliance provision. In addition,
0047  * Licensee must cause all Covered Code to which Licensee contributes to
0048  * contain a file documenting the changes Licensee made to create that Covered
0049  * Code and the date of any change. Licensee must include in that file the
0050  * documentation of any changes made by any predecessor Licensee. Licensee
0051  * must include a prominent statement that the modification is derived,
0052  * directly or indirectly, from Original Intel Code.
0053  *
0054  * 3.2. Redistribution of Source with no Rights to Further Distribute Source.
0055  * Redistribution of source code of any substantial portion of the Covered
0056  * Code or modification without rights to further distribute source must
0057  * include the following Disclaimer and Export Compliance provision in the
0058  * documentation and/or other materials provided with distribution. In
0059  * addition, Licensee may not authorize further sublicense of source of any
0060  * portion of the Covered Code, and must include terms to the effect that the
0061  * license from Licensee to its licensee is limited to the intellectual
0062  * property embodied in the software Licensee provides to its licensee, and
0063  * not to intellectual property embodied in modifications its licensee may
0064  * make.
0065  *
0066  * 3.3. Redistribution of Executable. Redistribution in executable form of any
0067  * substantial portion of the Covered Code or modification must reproduce the
0068  * above Copyright Notice, and the following Disclaimer and Export Compliance
0069  * provision in the documentation and/or other materials provided with the
0070  * distribution.
0071  *
0072  * 3.4. Intel retains all right, title, and interest in and to the Original
0073  * Intel Code.
0074  *
0075  * 3.5. Neither the name Intel nor any other trademark owned or controlled by
0076  * Intel shall be used in advertising or otherwise to promote the sale, use or
0077  * other dealings in products derived from or relating to the Covered Code
0078  * without prior written authorization from Intel.
0079  *
0080  * 4. Disclaimer and Export Compliance
0081  *
0082  * 4.1. INTEL MAKES NO WARRANTY OF ANY KIND REGARDING ANY SOFTWARE PROVIDED
0083  * HERE. ANY SOFTWARE ORIGINATING FROM INTEL OR DERIVED FROM INTEL SOFTWARE
0084  * IS PROVIDED "AS IS," AND INTEL WILL NOT PROVIDE ANY SUPPORT, ASSISTANCE,
0085  * INSTALLATION, TRAINING OR OTHER SERVICES. INTEL WILL NOT PROVIDE ANY
0086  * UPDATES, ENHANCEMENTS OR EXTENSIONS. INTEL SPECIFICALLY DISCLAIMS ANY
0087  * IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT AND FITNESS FOR A
0088  * PARTICULAR PURPOSE.
0089  *
0090  * 4.2. IN NO EVENT SHALL INTEL HAVE ANY LIABILITY TO LICENSEE, ITS LICENSEES
0091  * OR ANY OTHER THIRD PARTY, FOR ANY LOST PROFITS, LOST DATA, LOSS OF USE OR
0092  * COSTS OF PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY INDIRECT,
0093  * SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THIS AGREEMENT, UNDER ANY
0094  * CAUSE OF ACTION OR THEORY OF LIABILITY, AND IRRESPECTIVE OF WHETHER INTEL
0095  * HAS ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. THESE LIMITATIONS
0096  * SHALL APPLY NOTWITHSTANDING THE FAILURE OF THE ESSENTIAL PURPOSE OF ANY
0097  * LIMITED REMEDY.
0098  *
0099  * 4.3. Licensee shall not export, either directly or indirectly, any of this
0100  * software or system incorporating such software without first obtaining any
0101  * required license or other approval from the U. S. Department of Commerce or
0102  * any other agency or department of the United States Government. In the
0103  * event Licensee exports any such software from the United States or
0104  * re-exports any such software from a foreign destination, Licensee shall
0105  * ensure that the distribution and export/re-export of the software is in
0106  * compliance with all laws, regulations, orders, or other restrictions of the
0107  * U.S. Export Administration Regulations. Licensee agrees that neither it nor
0108  * any of its subsidiaries will export/re-export any technical data, process,
0109  * software, or service, directly or indirectly, to any country for which the
0110  * United States government or any agency thereof requires an export license,
0111  * other governmental approval, or letter of assurance, without first obtaining
0112  * such license, approval or letter.
0113  *
0114  *****************************************************************************
0115  *
0116  * Alternatively, you may choose to be licensed under the terms of the
0117  * following license:
0118  *
0119  * Redistribution and use in source and binary forms, with or without
0120  * modification, are permitted provided that the following conditions
0121  * are met:
0122  * 1. Redistributions of source code must retain the above copyright
0123  *    notice, this list of conditions, and the following disclaimer,
0124  *    without modification.
0125  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
0126  *    substantially similar to the "NO WARRANTY" disclaimer below
0127  *    ("Disclaimer") and any redistribution must be conditioned upon
0128  *    including a substantially similar Disclaimer requirement for further
0129  *    binary redistribution.
0130  * 3. Neither the names of the above-listed copyright holders nor the names
0131  *    of any contributors may be used to endorse or promote products derived
0132  *    from this software without specific prior written permission.
0133  *
0134  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
0135  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
0136  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
0137  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
0138  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
0139  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
0140  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
0141  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
0142  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
0143  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
0144  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
0145  *
0146  * Alternatively, you may choose to be licensed under the terms of the
0147  * GNU General Public License ("GPL") version 2 as published by the Free
0148  * Software Foundation.
0149  *
0150  *****************************************************************************/
0151 
0152 #include "acpi.h"
0153 #include "accommon.h"
0154 #include "acdispat.h"
0155 #include "acinterp.h"
0156 #include "acnamesp.h"
0157 #include "acparser.h"
0158 #include "amlcode.h"
0159 #include "acdebug.h"
0160 
0161 
0162 #define _COMPONENT          ACPI_DISPATCHER
0163         ACPI_MODULE_NAME    ("dsmethod")
0164 
0165 /* Local prototypes */
0166 
0167 static ACPI_STATUS
0168 AcpiDsDetectNamedOpcodes (
0169     ACPI_WALK_STATE         *WalkState,
0170     ACPI_PARSE_OBJECT       **OutOp);
0171 
0172 static ACPI_STATUS
0173 AcpiDsCreateMethodMutex (
0174     ACPI_OPERAND_OBJECT     *MethodDesc);
0175 
0176 
0177 /*******************************************************************************
0178  *
0179  * FUNCTION:    AcpiDsAutoSerializeMethod
0180  *
0181  * PARAMETERS:  Node                        - Namespace Node of the method
0182  *              ObjDesc                     - Method object attached to node
0183  *
0184  * RETURN:      Status
0185  *
0186  * DESCRIPTION: Parse a control method AML to scan for control methods that
0187  *              need serialization due to the creation of named objects.
0188  *
0189  * NOTE: It is a bit of overkill to mark all such methods serialized, since
0190  * there is only a problem if the method actually blocks during execution.
0191  * A blocking operation is, for example, a Sleep() operation, or any access
0192  * to an operation region. However, it is probably not possible to easily
0193  * detect whether a method will block or not, so we simply mark all suspicious
0194  * methods as serialized.
0195  *
0196  * NOTE2: This code is essentially a generic routine for parsing a single
0197  * control method.
0198  *
0199  ******************************************************************************/
0200 
0201 ACPI_STATUS
0202 AcpiDsAutoSerializeMethod (
0203     ACPI_NAMESPACE_NODE     *Node,
0204     ACPI_OPERAND_OBJECT     *ObjDesc)
0205 {
0206     ACPI_STATUS             Status;
0207     ACPI_PARSE_OBJECT       *Op = NULL;
0208     ACPI_WALK_STATE         *WalkState;
0209 
0210 
0211     ACPI_FUNCTION_TRACE_PTR (DsAutoSerializeMethod, Node);
0212 
0213 
0214     ACPI_DEBUG_PRINT ((ACPI_DB_PARSE,
0215         "Method auto-serialization parse [%4.4s] %p\n",
0216         AcpiUtGetNodeName (Node), Node));
0217 
0218     /* Create/Init a root op for the method parse tree */
0219 
0220     Op = AcpiPsAllocOp (AML_METHOD_OP, ObjDesc->Method.AmlStart);
0221     if (!Op)
0222     {
0223         return_ACPI_STATUS (AE_NO_MEMORY);
0224     }
0225 
0226     AcpiPsSetName (Op, Node->Name.Integer);
0227     Op->Common.Node = Node;
0228 
0229     /* Create and initialize a new walk state */
0230 
0231     WalkState = AcpiDsCreateWalkState (Node->OwnerId, NULL, NULL, NULL);
0232     if (!WalkState)
0233     {
0234         AcpiPsFreeOp (Op);
0235         return_ACPI_STATUS (AE_NO_MEMORY);
0236     }
0237 
0238     Status = AcpiDsInitAmlWalk (WalkState, Op, Node,
0239         ObjDesc->Method.AmlStart, ObjDesc->Method.AmlLength, NULL, 0);
0240     if (ACPI_FAILURE (Status))
0241     {
0242         AcpiDsDeleteWalkState (WalkState);
0243         AcpiPsFreeOp (Op);
0244         return_ACPI_STATUS (Status);
0245     }
0246 
0247     WalkState->DescendingCallback = AcpiDsDetectNamedOpcodes;
0248 
0249     /* Parse the method, scan for creation of named objects */
0250 
0251     Status = AcpiPsParseAml (WalkState);
0252 
0253     AcpiPsDeleteParseTree (Op);
0254     return_ACPI_STATUS (Status);
0255 }
0256 
0257 
0258 /*******************************************************************************
0259  *
0260  * FUNCTION:    AcpiDsDetectNamedOpcodes
0261  *
0262  * PARAMETERS:  WalkState       - Current state of the parse tree walk
0263  *              OutOp           - Unused, required for parser interface
0264  *
0265  * RETURN:      Status
0266  *
0267  * DESCRIPTION: Descending callback used during the loading of ACPI tables.
0268  *              Currently used to detect methods that must be marked serialized
0269  *              in order to avoid problems with the creation of named objects.
0270  *
0271  ******************************************************************************/
0272 
0273 static ACPI_STATUS
0274 AcpiDsDetectNamedOpcodes (
0275     ACPI_WALK_STATE         *WalkState,
0276     ACPI_PARSE_OBJECT       **OutOp)
0277 {
0278 
0279     ACPI_FUNCTION_NAME (AcpiDsDetectNamedOpcodes);
0280 
0281 
0282     /* We are only interested in opcodes that create a new name */
0283 
0284     if (!(WalkState->OpInfo->Flags & (AML_NAMED | AML_CREATE | AML_FIELD)))
0285     {
0286         return (AE_OK);
0287     }
0288 
0289     /*
0290      * At this point, we know we have a Named object opcode.
0291      * Mark the method as serialized. Later code will create a mutex for
0292      * this method to enforce serialization.
0293      *
0294      * Note, ACPI_METHOD_IGNORE_SYNC_LEVEL flag means that we will ignore the
0295      * Sync Level mechanism for this method, even though it is now serialized.
0296      * Otherwise, there can be conflicts with existing ASL code that actually
0297      * uses sync levels.
0298      */
0299     WalkState->MethodDesc->Method.SyncLevel = 0;
0300     WalkState->MethodDesc->Method.InfoFlags |=
0301         (ACPI_METHOD_SERIALIZED | ACPI_METHOD_IGNORE_SYNC_LEVEL);
0302 
0303     ACPI_DEBUG_PRINT ((ACPI_DB_INFO,
0304         "Method serialized [%4.4s] %p - [%s] (%4.4X)\n",
0305         WalkState->MethodNode->Name.Ascii, WalkState->MethodNode,
0306         WalkState->OpInfo->Name, WalkState->Opcode));
0307 
0308     /* Abort the parse, no need to examine this method any further */
0309 
0310     return (AE_CTRL_TERMINATE);
0311 }
0312 
0313 
0314 /*******************************************************************************
0315  *
0316  * FUNCTION:    AcpiDsMethodError
0317  *
0318  * PARAMETERS:  Status          - Execution status
0319  *              WalkState       - Current state
0320  *
0321  * RETURN:      Status
0322  *
0323  * DESCRIPTION: Called on method error. Invoke the global exception handler if
0324  *              present, dump the method data if the debugger is configured
0325  *
0326  *              Note: Allows the exception handler to change the status code
0327  *
0328  ******************************************************************************/
0329 
0330 ACPI_STATUS
0331 AcpiDsMethodError (
0332     ACPI_STATUS             Status,
0333     ACPI_WALK_STATE         *WalkState)
0334 {
0335     UINT32                  AmlOffset;
0336     ACPI_NAME               Name = 0;
0337 
0338 
0339     ACPI_FUNCTION_ENTRY ();
0340 
0341 
0342     /* Ignore AE_OK and control exception codes */
0343 
0344     if (ACPI_SUCCESS (Status) ||
0345         (Status & AE_CODE_CONTROL))
0346     {
0347         return (Status);
0348     }
0349 
0350     /* Invoke the global exception handler */
0351 
0352     if (AcpiGbl_ExceptionHandler)
0353     {
0354         /* Exit the interpreter, allow handler to execute methods */
0355 
0356         AcpiExExitInterpreter ();
0357 
0358         /*
0359          * Handler can map the exception code to anything it wants, including
0360          * AE_OK, in which case the executing method will not be aborted.
0361          */
0362         AmlOffset = (UINT32) ACPI_PTR_DIFF (WalkState->Aml,
0363             WalkState->ParserState.AmlStart);
0364 
0365         if (WalkState->MethodNode)
0366         {
0367             Name = WalkState->MethodNode->Name.Integer;
0368         }
0369         else if (WalkState->DeferredNode)
0370         {
0371             Name = WalkState->DeferredNode->Name.Integer;
0372         }
0373 
0374         Status = AcpiGbl_ExceptionHandler (Status, Name,
0375             WalkState->Opcode, AmlOffset, NULL);
0376         AcpiExEnterInterpreter ();
0377     }
0378 
0379     AcpiDsClearImplicitReturn (WalkState);
0380 
0381     if (ACPI_FAILURE (Status))
0382     {
0383         AcpiDsDumpMethodStack (Status, WalkState, WalkState->Op);
0384 
0385         /* Display method locals/args if debugger is present */
0386 
0387 #ifdef ACPI_DEBUGGER
0388         AcpiDbDumpMethodInfo (Status, WalkState);
0389 #endif
0390     }
0391 
0392     return (Status);
0393 }
0394 
0395 
0396 /*******************************************************************************
0397  *
0398  * FUNCTION:    AcpiDsCreateMethodMutex
0399  *
0400  * PARAMETERS:  ObjDesc             - The method object
0401  *
0402  * RETURN:      Status
0403  *
0404  * DESCRIPTION: Create a mutex object for a serialized control method
0405  *
0406  ******************************************************************************/
0407 
0408 static ACPI_STATUS
0409 AcpiDsCreateMethodMutex (
0410     ACPI_OPERAND_OBJECT     *MethodDesc)
0411 {
0412     ACPI_OPERAND_OBJECT     *MutexDesc;
0413     ACPI_STATUS             Status;
0414 
0415 
0416     ACPI_FUNCTION_TRACE (DsCreateMethodMutex);
0417 
0418 
0419     /* Create the new mutex object */
0420 
0421     MutexDesc = AcpiUtCreateInternalObject (ACPI_TYPE_MUTEX);
0422     if (!MutexDesc)
0423     {
0424         return_ACPI_STATUS (AE_NO_MEMORY);
0425     }
0426 
0427     /* Create the actual OS Mutex */
0428 
0429     Status = AcpiOsCreateMutex (&MutexDesc->Mutex.OsMutex);
0430     if (ACPI_FAILURE (Status))
0431     {
0432         AcpiUtDeleteObjectDesc (MutexDesc);
0433         return_ACPI_STATUS (Status);
0434     }
0435 
0436     MutexDesc->Mutex.SyncLevel = MethodDesc->Method.SyncLevel;
0437     MethodDesc->Method.Mutex = MutexDesc;
0438     return_ACPI_STATUS (AE_OK);
0439 }
0440 
0441 
0442 /*******************************************************************************
0443  *
0444  * FUNCTION:    AcpiDsBeginMethodExecution
0445  *
0446  * PARAMETERS:  MethodNode          - Node of the method
0447  *              ObjDesc             - The method object
0448  *              WalkState           - current state, NULL if not yet executing
0449  *                                    a method.
0450  *
0451  * RETURN:      Status
0452  *
0453  * DESCRIPTION: Prepare a method for execution. Parses the method if necessary,
0454  *              increments the thread count, and waits at the method semaphore
0455  *              for clearance to execute.
0456  *
0457  ******************************************************************************/
0458 
0459 ACPI_STATUS
0460 AcpiDsBeginMethodExecution (
0461     ACPI_NAMESPACE_NODE     *MethodNode,
0462     ACPI_OPERAND_OBJECT     *ObjDesc,
0463     ACPI_WALK_STATE         *WalkState)
0464 {
0465     ACPI_STATUS             Status = AE_OK;
0466 
0467 
0468     ACPI_FUNCTION_TRACE_PTR (DsBeginMethodExecution, MethodNode);
0469 
0470 
0471     if (!MethodNode)
0472     {
0473         return_ACPI_STATUS (AE_NULL_ENTRY);
0474     }
0475 
0476     AcpiExStartTraceMethod (MethodNode, ObjDesc, WalkState);
0477 
0478     /* Prevent wraparound of thread count */
0479 
0480     if (ObjDesc->Method.ThreadCount == ACPI_UINT8_MAX)
0481     {
0482         ACPI_ERROR ((AE_INFO,
0483             "Method reached maximum reentrancy limit (255)"));
0484         return_ACPI_STATUS (AE_AML_METHOD_LIMIT);
0485     }
0486 
0487     /*
0488      * If this method is serialized, we need to acquire the method mutex.
0489      */
0490     if (ObjDesc->Method.InfoFlags & ACPI_METHOD_SERIALIZED)
0491     {
0492         /*
0493          * Create a mutex for the method if it is defined to be Serialized
0494          * and a mutex has not already been created. We defer the mutex creation
0495          * until a method is actually executed, to minimize the object count
0496          */
0497         if (!ObjDesc->Method.Mutex)
0498         {
0499             Status = AcpiDsCreateMethodMutex (ObjDesc);
0500             if (ACPI_FAILURE (Status))
0501             {
0502                 return_ACPI_STATUS (Status);
0503             }
0504         }
0505 
0506         /*
0507          * The CurrentSyncLevel (per-thread) must be less than or equal to
0508          * the sync level of the method. This mechanism provides some
0509          * deadlock prevention.
0510          *
0511          * If the method was auto-serialized, we just ignore the sync level
0512          * mechanism, because auto-serialization of methods can interfere
0513          * with ASL code that actually uses sync levels.
0514          *
0515          * Top-level method invocation has no walk state at this point
0516          */
0517         if (WalkState &&
0518             (!(ObjDesc->Method.InfoFlags & ACPI_METHOD_IGNORE_SYNC_LEVEL)) &&
0519             (WalkState->Thread->CurrentSyncLevel >
0520                 ObjDesc->Method.Mutex->Mutex.SyncLevel))
0521         {
0522             ACPI_ERROR ((AE_INFO,
0523                 "Cannot acquire Mutex for method [%4.4s]"
0524                 ", current SyncLevel is too large (%u)",
0525                 AcpiUtGetNodeName (MethodNode),
0526                 WalkState->Thread->CurrentSyncLevel));
0527 
0528             return_ACPI_STATUS (AE_AML_MUTEX_ORDER);
0529         }
0530 
0531         /*
0532          * Obtain the method mutex if necessary. Do not acquire mutex for a
0533          * recursive call.
0534          */
0535         if (!WalkState ||
0536             !ObjDesc->Method.Mutex->Mutex.ThreadId ||
0537             (WalkState->Thread->ThreadId !=
0538                 ObjDesc->Method.Mutex->Mutex.ThreadId))
0539         {
0540             /*
0541              * Acquire the method mutex. This releases the interpreter if we
0542              * block (and reacquires it before it returns)
0543              */
0544             Status = AcpiExSystemWaitMutex (
0545                 ObjDesc->Method.Mutex->Mutex.OsMutex, ACPI_WAIT_FOREVER);
0546             if (ACPI_FAILURE (Status))
0547             {
0548                 return_ACPI_STATUS (Status);
0549             }
0550 
0551             /* Update the mutex and walk info and save the original SyncLevel */
0552 
0553             if (WalkState)
0554             {
0555                 ObjDesc->Method.Mutex->Mutex.OriginalSyncLevel =
0556                     WalkState->Thread->CurrentSyncLevel;
0557 
0558                 ObjDesc->Method.Mutex->Mutex.ThreadId =
0559                     WalkState->Thread->ThreadId;
0560 
0561                 /*
0562                  * Update the current SyncLevel only if this is not an auto-
0563                  * serialized method. In the auto case, we have to ignore
0564                  * the sync level for the method mutex (created for the
0565                  * auto-serialization) because we have no idea of what the
0566                  * sync level should be. Therefore, just ignore it.
0567                  */
0568                 if (!(ObjDesc->Method.InfoFlags &
0569                     ACPI_METHOD_IGNORE_SYNC_LEVEL))
0570                 {
0571                     WalkState->Thread->CurrentSyncLevel =
0572                         ObjDesc->Method.SyncLevel;
0573                 }
0574             }
0575             else
0576             {
0577                 ObjDesc->Method.Mutex->Mutex.OriginalSyncLevel =
0578                     ObjDesc->Method.Mutex->Mutex.SyncLevel;
0579 
0580                 ObjDesc->Method.Mutex->Mutex.ThreadId =
0581                     AcpiOsGetThreadId ();
0582             }
0583         }
0584 
0585         /* Always increase acquisition depth */
0586 
0587         ObjDesc->Method.Mutex->Mutex.AcquisitionDepth++;
0588     }
0589 
0590     /*
0591      * Allocate an Owner ID for this method, only if this is the first thread
0592      * to begin concurrent execution. We only need one OwnerId, even if the
0593      * method is invoked recursively.
0594      */
0595     if (!ObjDesc->Method.OwnerId)
0596     {
0597         Status = AcpiUtAllocateOwnerId (&ObjDesc->Method.OwnerId);
0598         if (ACPI_FAILURE (Status))
0599         {
0600             goto Cleanup;
0601         }
0602     }
0603 
0604     /*
0605      * Increment the method parse tree thread count since it has been
0606      * reentered one more time (even if it is the same thread)
0607      */
0608     ObjDesc->Method.ThreadCount++;
0609     AcpiMethodCount++;
0610     return_ACPI_STATUS (Status);
0611 
0612 
0613 Cleanup:
0614     /* On error, must release the method mutex (if present) */
0615 
0616     if (ObjDesc->Method.Mutex)
0617     {
0618         AcpiOsReleaseMutex (ObjDesc->Method.Mutex->Mutex.OsMutex);
0619     }
0620     return_ACPI_STATUS (Status);
0621 }
0622 
0623 
0624 /*******************************************************************************
0625  *
0626  * FUNCTION:    AcpiDsCallControlMethod
0627  *
0628  * PARAMETERS:  Thread              - Info for this thread
0629  *              ThisWalkState       - Current walk state
0630  *              Op                  - Current Op to be walked
0631  *
0632  * RETURN:      Status
0633  *
0634  * DESCRIPTION: Transfer execution to a called control method
0635  *
0636  ******************************************************************************/
0637 
0638 ACPI_STATUS
0639 AcpiDsCallControlMethod (
0640     ACPI_THREAD_STATE       *Thread,
0641     ACPI_WALK_STATE         *ThisWalkState,
0642     ACPI_PARSE_OBJECT       *Op)
0643 {
0644     ACPI_STATUS             Status;
0645     ACPI_NAMESPACE_NODE     *MethodNode;
0646     ACPI_WALK_STATE         *NextWalkState = NULL;
0647     ACPI_OPERAND_OBJECT     *ObjDesc;
0648     ACPI_EVALUATE_INFO      *Info;
0649     UINT32                  i;
0650 
0651 
0652     ACPI_FUNCTION_TRACE_PTR (DsCallControlMethod, ThisWalkState);
0653 
0654     ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
0655         "Calling method %p, currentstate=%p\n",
0656         ThisWalkState->PrevOp, ThisWalkState));
0657 
0658     /*
0659      * Get the namespace entry for the control method we are about to call
0660      */
0661     MethodNode = ThisWalkState->MethodCallNode;
0662     if (!MethodNode)
0663     {
0664         return_ACPI_STATUS (AE_NULL_ENTRY);
0665     }
0666 
0667     ObjDesc = AcpiNsGetAttachedObject (MethodNode);
0668     if (!ObjDesc)
0669     {
0670         return_ACPI_STATUS (AE_NULL_OBJECT);
0671     }
0672 
0673     /* Init for new method, possibly wait on method mutex */
0674 
0675     Status = AcpiDsBeginMethodExecution (
0676         MethodNode, ObjDesc, ThisWalkState);
0677     if (ACPI_FAILURE (Status))
0678     {
0679         return_ACPI_STATUS (Status);
0680     }
0681 
0682     /* Begin method parse/execution. Create a new walk state */
0683 
0684     NextWalkState = AcpiDsCreateWalkState (
0685         ObjDesc->Method.OwnerId, NULL, ObjDesc, Thread);
0686     if (!NextWalkState)
0687     {
0688         Status = AE_NO_MEMORY;
0689         goto Cleanup;
0690     }
0691 
0692     /*
0693      * The resolved arguments were put on the previous walk state's operand
0694      * stack. Operands on the previous walk state stack always
0695      * start at index 0. Also, null terminate the list of arguments
0696      */
0697     ThisWalkState->Operands [ThisWalkState->NumOperands] = NULL;
0698 
0699     /*
0700      * Allocate and initialize the evaluation information block
0701      * TBD: this is somewhat inefficient, should change interface to
0702      * DsInitAmlWalk. For now, keeps this struct off the CPU stack
0703      */
0704     Info = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_EVALUATE_INFO));
0705     if (!Info)
0706     {
0707         Status = AE_NO_MEMORY;
0708         goto PopWalkState;
0709     }
0710 
0711     Info->Parameters = &ThisWalkState->Operands[0];
0712 
0713     Status = AcpiDsInitAmlWalk (NextWalkState, NULL, MethodNode,
0714         ObjDesc->Method.AmlStart, ObjDesc->Method.AmlLength,
0715         Info, ACPI_IMODE_EXECUTE);
0716 
0717     ACPI_FREE (Info);
0718     if (ACPI_FAILURE (Status))
0719     {
0720         goto PopWalkState;
0721     }
0722 
0723     NextWalkState->MethodNestingDepth = ThisWalkState->MethodNestingDepth + 1;
0724 
0725     /*
0726      * Delete the operands on the previous walkstate operand stack
0727      * (they were copied to new objects)
0728      */
0729     for (i = 0; i < ObjDesc->Method.ParamCount; i++)
0730     {
0731         AcpiUtRemoveReference (ThisWalkState->Operands [i]);
0732         ThisWalkState->Operands [i] = NULL;
0733     }
0734 
0735     /* Clear the operand stack */
0736 
0737     ThisWalkState->NumOperands = 0;
0738 
0739     ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
0740         "**** Begin nested execution of [%4.4s] **** WalkState=%p\n",
0741         MethodNode->Name.Ascii, NextWalkState));
0742 
0743     ThisWalkState->MethodPathname = AcpiNsGetNormalizedPathname (MethodNode, TRUE);
0744     ThisWalkState->MethodIsNested = TRUE;
0745 
0746     /* Optional object evaluation log */
0747 
0748     ACPI_DEBUG_PRINT_RAW ((ACPI_DB_EVALUATION,
0749         "%-26s:  %*s%s\n", "   Nested method call",
0750         NextWalkState->MethodNestingDepth * 3, " ",
0751         &ThisWalkState->MethodPathname[1]));
0752 
0753     /* Invoke an internal method if necessary */
0754 
0755     if (ObjDesc->Method.InfoFlags & ACPI_METHOD_INTERNAL_ONLY)
0756     {
0757         Status = ObjDesc->Method.Dispatch.Implementation (NextWalkState);
0758         if (Status == AE_OK)
0759         {
0760             Status = AE_CTRL_TERMINATE;
0761         }
0762     }
0763 
0764     return_ACPI_STATUS (Status);
0765 
0766 
0767 PopWalkState:
0768 
0769     /* On error, pop the walk state to be deleted from thread */
0770 
0771     AcpiDsPopWalkState(Thread);
0772 
0773 Cleanup:
0774 
0775     /* On error, we must terminate the method properly */
0776 
0777     AcpiDsTerminateControlMethod (ObjDesc, NextWalkState);
0778     AcpiDsDeleteWalkState (NextWalkState);
0779 
0780     return_ACPI_STATUS (Status);
0781 }
0782 
0783 
0784 /*******************************************************************************
0785  *
0786  * FUNCTION:    AcpiDsRestartControlMethod
0787  *
0788  * PARAMETERS:  WalkState           - State for preempted method (caller)
0789  *              ReturnDesc          - Return value from the called method
0790  *
0791  * RETURN:      Status
0792  *
0793  * DESCRIPTION: Restart a method that was preempted by another (nested) method
0794  *              invocation. Handle the return value (if any) from the callee.
0795  *
0796  ******************************************************************************/
0797 
0798 ACPI_STATUS
0799 AcpiDsRestartControlMethod (
0800     ACPI_WALK_STATE         *WalkState,
0801     ACPI_OPERAND_OBJECT     *ReturnDesc)
0802 {
0803     ACPI_STATUS             Status;
0804     int                     SameAsImplicitReturn;
0805 
0806 
0807     ACPI_FUNCTION_TRACE_PTR (DsRestartControlMethod, WalkState);
0808 
0809 
0810     ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
0811         "****Restart [%4.4s] Op %p ReturnValueFromCallee %p\n",
0812         AcpiUtGetNodeName (WalkState->MethodNode),
0813         WalkState->MethodCallOp, ReturnDesc));
0814 
0815     ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
0816         "    ReturnFromThisMethodUsed?=%X ResStack %p Walk %p\n",
0817         WalkState->ReturnUsed,
0818         WalkState->Results, WalkState));
0819 
0820     /* Did the called method return a value? */
0821 
0822     if (ReturnDesc)
0823     {
0824         /* Is the implicit return object the same as the return desc? */
0825 
0826         SameAsImplicitReturn = (WalkState->ImplicitReturnObj == ReturnDesc);
0827 
0828         /* Are we actually going to use the return value? */
0829 
0830         if (WalkState->ReturnUsed)
0831         {
0832             /* Save the return value from the previous method */
0833 
0834             Status = AcpiDsResultPush (ReturnDesc, WalkState);
0835             if (ACPI_FAILURE (Status))
0836             {
0837                 AcpiUtRemoveReference (ReturnDesc);
0838                 return_ACPI_STATUS (Status);
0839             }
0840 
0841             /*
0842              * Save as THIS method's return value in case it is returned
0843              * immediately to yet another method
0844              */
0845             WalkState->ReturnDesc = ReturnDesc;
0846         }
0847 
0848         /*
0849          * The following code is the optional support for the so-called
0850          * "implicit return". Some AML code assumes that the last value of the
0851          * method is "implicitly" returned to the caller, in the absence of an
0852          * explicit return value.
0853          *
0854          * Just save the last result of the method as the return value.
0855          *
0856          * NOTE: this is optional because the ASL language does not actually
0857          * support this behavior.
0858          */
0859         else if (!AcpiDsDoImplicitReturn (ReturnDesc, WalkState, FALSE) ||
0860                  SameAsImplicitReturn)
0861         {
0862             /*
0863              * Delete the return value if it will not be used by the
0864              * calling method or remove one reference if the explicit return
0865              * is the same as the implicit return value.
0866              */
0867             AcpiUtRemoveReference (ReturnDesc);
0868         }
0869     }
0870 
0871     return_ACPI_STATUS (AE_OK);
0872 }
0873 
0874 
0875 /*******************************************************************************
0876  *
0877  * FUNCTION:    AcpiDsTerminateControlMethod
0878  *
0879  * PARAMETERS:  MethodDesc          - Method object
0880  *              WalkState           - State associated with the method
0881  *
0882  * RETURN:      None
0883  *
0884  * DESCRIPTION: Terminate a control method. Delete everything that the method
0885  *              created, delete all locals and arguments, and delete the parse
0886  *              tree if requested.
0887  *
0888  * MUTEX:       Interpreter is locked
0889  *
0890  ******************************************************************************/
0891 
0892 void
0893 AcpiDsTerminateControlMethod (
0894     ACPI_OPERAND_OBJECT     *MethodDesc,
0895     ACPI_WALK_STATE         *WalkState)
0896 {
0897 
0898     ACPI_FUNCTION_TRACE_PTR (DsTerminateControlMethod, WalkState);
0899 
0900 
0901     /* MethodDesc is required, WalkState is optional */
0902 
0903     if (!MethodDesc)
0904     {
0905         return_VOID;
0906     }
0907 
0908     if (WalkState)
0909     {
0910         /* Delete all arguments and locals */
0911 
0912         AcpiDsMethodDataDeleteAll (WalkState);
0913 
0914         /*
0915          * Delete any namespace objects created anywhere within the
0916          * namespace by the execution of this method. Unless:
0917          * 1) This method is a module-level executable code method, in which
0918          *    case we want make the objects permanent.
0919          * 2) There are other threads executing the method, in which case we
0920          *    will wait until the last thread has completed.
0921          */
0922         if (!(MethodDesc->Method.InfoFlags & ACPI_METHOD_MODULE_LEVEL) &&
0923              (MethodDesc->Method.ThreadCount == 1))
0924         {
0925             /* Delete any direct children of (created by) this method */
0926 
0927             (void) AcpiExExitInterpreter ();
0928             AcpiNsDeleteNamespaceSubtree (WalkState->MethodNode);
0929             (void) AcpiExEnterInterpreter ();
0930 
0931             /*
0932              * Delete any objects that were created by this method
0933              * elsewhere in the namespace (if any were created).
0934              * Use of the ACPI_METHOD_MODIFIED_NAMESPACE optimizes the
0935              * deletion such that we don't have to perform an entire
0936              * namespace walk for every control method execution.
0937              */
0938             if (MethodDesc->Method.InfoFlags & ACPI_METHOD_MODIFIED_NAMESPACE)
0939             {
0940                 (void) AcpiExExitInterpreter ();
0941                 AcpiNsDeleteNamespaceByOwner (MethodDesc->Method.OwnerId);
0942                 (void) AcpiExEnterInterpreter ();
0943                 MethodDesc->Method.InfoFlags &=
0944                     ~ACPI_METHOD_MODIFIED_NAMESPACE;
0945             }
0946         }
0947 
0948         /*
0949          * If method is serialized, release the mutex and restore the
0950          * current sync level for this thread
0951          */
0952         if (MethodDesc->Method.Mutex)
0953         {
0954             /* Acquisition Depth handles recursive calls */
0955 
0956             MethodDesc->Method.Mutex->Mutex.AcquisitionDepth--;
0957             if (!MethodDesc->Method.Mutex->Mutex.AcquisitionDepth)
0958             {
0959                 WalkState->Thread->CurrentSyncLevel =
0960                     MethodDesc->Method.Mutex->Mutex.OriginalSyncLevel;
0961 
0962                 AcpiOsReleaseMutex (
0963                     MethodDesc->Method.Mutex->Mutex.OsMutex);
0964                 MethodDesc->Method.Mutex->Mutex.ThreadId = 0;
0965             }
0966         }
0967     }
0968 
0969     /* Decrement the thread count on the method */
0970 
0971     if (MethodDesc->Method.ThreadCount)
0972     {
0973         MethodDesc->Method.ThreadCount--;
0974     }
0975     else
0976     {
0977         ACPI_ERROR ((AE_INFO,
0978             "Invalid zero thread count in method"));
0979     }
0980 
0981     /* Are there any other threads currently executing this method? */
0982 
0983     if (MethodDesc->Method.ThreadCount)
0984     {
0985         /*
0986          * Additional threads. Do not release the OwnerId in this case,
0987          * we immediately reuse it for the next thread executing this method
0988          */
0989         ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
0990             "*** Completed execution of one thread, %u threads remaining\n",
0991             MethodDesc->Method.ThreadCount));
0992     }
0993     else
0994     {
0995         /* This is the only executing thread for this method */
0996 
0997         /*
0998          * Support to dynamically change a method from NotSerialized to
0999          * Serialized if it appears that the method is incorrectly written and
1000          * does not support multiple thread execution. The best example of this
1001          * is if such a method creates namespace objects and blocks. A second
1002          * thread will fail with an AE_ALREADY_EXISTS exception.
1003          *
1004          * This code is here because we must wait until the last thread exits
1005          * before marking the method as serialized.
1006          */
1007         if (MethodDesc->Method.InfoFlags & ACPI_METHOD_SERIALIZED_PENDING)
1008         {
1009             if (WalkState)
1010             {
1011                 ACPI_INFO ((
1012                     "Marking method %4.4s as Serialized "
1013                     "because of AE_ALREADY_EXISTS error",
1014                     WalkState->MethodNode->Name.Ascii));
1015             }
1016 
1017             /*
1018              * Method tried to create an object twice and was marked as
1019              * "pending serialized". The probable cause is that the method
1020              * cannot handle reentrancy.
1021              *
1022              * The method was created as NotSerialized, but it tried to create
1023              * a named object and then blocked, causing the second thread
1024              * entrance to begin and then fail. Workaround this problem by
1025              * marking the method permanently as Serialized when the last
1026              * thread exits here.
1027              */
1028             MethodDesc->Method.InfoFlags &=
1029                 ~ACPI_METHOD_SERIALIZED_PENDING;
1030 
1031             MethodDesc->Method.InfoFlags |=
1032                 (ACPI_METHOD_SERIALIZED | ACPI_METHOD_IGNORE_SYNC_LEVEL);
1033             MethodDesc->Method.SyncLevel = 0;
1034         }
1035 
1036         /* No more threads, we can free the OwnerId */
1037 
1038         if (!(MethodDesc->Method.InfoFlags & ACPI_METHOD_MODULE_LEVEL))
1039         {
1040             AcpiUtReleaseOwnerId (&MethodDesc->Method.OwnerId);
1041         }
1042     }
1043 
1044     AcpiExStopTraceMethod ((ACPI_NAMESPACE_NODE *) MethodDesc->Method.Node,
1045         MethodDesc, WalkState);
1046 
1047     return_VOID;
1048 }