Home | History | Annotate | Line # | Download | only in dispatcher
dsmethod.c revision 1.1.1.19
      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.19  christos /******************************************************************************
      8  1.1.1.19  christos  *
      9  1.1.1.19  christos  * 1. Copyright Notice
     10  1.1.1.19  christos  *
     11  1.1.1.19  christos  * Some or all of this work - Copyright (c) 1999 - 2024, Intel Corp.
     12       1.1    jruoho  * All rights reserved.
     13       1.1    jruoho  *
     14  1.1.1.19  christos  * 2. License
     15  1.1.1.19  christos  *
     16  1.1.1.19  christos  * 2.1. This is your license from Intel Corp. under its intellectual property
     17  1.1.1.19  christos  * rights. You may have additional license terms from the party that provided
     18  1.1.1.19  christos  * you this software, covering your right to use that party's intellectual
     19  1.1.1.19  christos  * property rights.
     20  1.1.1.19  christos  *
     21  1.1.1.19  christos  * 2.2. Intel grants, free of charge, to any person ("Licensee") obtaining a
     22  1.1.1.19  christos  * copy of the source code appearing in this file ("Covered Code") an
     23  1.1.1.19  christos  * irrevocable, perpetual, worldwide license under Intel's copyrights in the
     24  1.1.1.19  christos  * base code distributed originally by Intel ("Original Intel Code") to copy,
     25  1.1.1.19  christos  * make derivatives, distribute, use and display any portion of the Covered
     26  1.1.1.19  christos  * Code in any form, with the right to sublicense such rights; and
     27  1.1.1.19  christos  *
     28  1.1.1.19  christos  * 2.3. Intel grants Licensee a non-exclusive and non-transferable patent
     29  1.1.1.19  christos  * license (with the right to sublicense), under only those claims of Intel
     30  1.1.1.19  christos  * patents that are infringed by the Original Intel Code, to make, use, sell,
     31  1.1.1.19  christos  * offer to sell, and import the Covered Code and derivative works thereof
     32  1.1.1.19  christos  * solely to the minimum extent necessary to exercise the above copyright
     33  1.1.1.19  christos  * license, and in no event shall the patent license extend to any additions
     34  1.1.1.19  christos  * to or modifications of the Original Intel Code. No other license or right
     35  1.1.1.19  christos  * is granted directly or by implication, estoppel or otherwise;
     36  1.1.1.19  christos  *
     37  1.1.1.19  christos  * The above copyright and patent license is granted only if the following
     38  1.1.1.19  christos  * conditions are met:
     39  1.1.1.19  christos  *
     40  1.1.1.19  christos  * 3. Conditions
     41  1.1.1.19  christos  *
     42  1.1.1.19  christos  * 3.1. Redistribution of Source with Rights to Further Distribute Source.
     43  1.1.1.19  christos  * Redistribution of source code of any substantial portion of the Covered
     44  1.1.1.19  christos  * Code or modification with rights to further distribute source must include
     45  1.1.1.19  christos  * the above Copyright Notice, the above License, this list of Conditions,
     46  1.1.1.19  christos  * and the following Disclaimer and Export Compliance provision. In addition,
     47  1.1.1.19  christos  * Licensee must cause all Covered Code to which Licensee contributes to
     48  1.1.1.19  christos  * contain a file documenting the changes Licensee made to create that Covered
     49  1.1.1.19  christos  * Code and the date of any change. Licensee must include in that file the
     50  1.1.1.19  christos  * documentation of any changes made by any predecessor Licensee. Licensee
     51  1.1.1.19  christos  * must include a prominent statement that the modification is derived,
     52  1.1.1.19  christos  * directly or indirectly, from Original Intel Code.
     53  1.1.1.19  christos  *
     54  1.1.1.19  christos  * 3.2. Redistribution of Source with no Rights to Further Distribute Source.
     55  1.1.1.19  christos  * Redistribution of source code of any substantial portion of the Covered
     56  1.1.1.19  christos  * Code or modification without rights to further distribute source must
     57  1.1.1.19  christos  * include the following Disclaimer and Export Compliance provision in the
     58  1.1.1.19  christos  * documentation and/or other materials provided with distribution. In
     59  1.1.1.19  christos  * addition, Licensee may not authorize further sublicense of source of any
     60  1.1.1.19  christos  * portion of the Covered Code, and must include terms to the effect that the
     61  1.1.1.19  christos  * license from Licensee to its licensee is limited to the intellectual
     62  1.1.1.19  christos  * property embodied in the software Licensee provides to its licensee, and
     63  1.1.1.19  christos  * not to intellectual property embodied in modifications its licensee may
     64  1.1.1.19  christos  * make.
     65  1.1.1.19  christos  *
     66  1.1.1.19  christos  * 3.3. Redistribution of Executable. Redistribution in executable form of any
     67  1.1.1.19  christos  * substantial portion of the Covered Code or modification must reproduce the
     68  1.1.1.19  christos  * above Copyright Notice, and the following Disclaimer and Export Compliance
     69  1.1.1.19  christos  * provision in the documentation and/or other materials provided with the
     70  1.1.1.19  christos  * distribution.
     71  1.1.1.19  christos  *
     72  1.1.1.19  christos  * 3.4. Intel retains all right, title, and interest in and to the Original
     73  1.1.1.19  christos  * Intel Code.
     74  1.1.1.19  christos  *
     75  1.1.1.19  christos  * 3.5. Neither the name Intel nor any other trademark owned or controlled by
     76  1.1.1.19  christos  * Intel shall be used in advertising or otherwise to promote the sale, use or
     77  1.1.1.19  christos  * other dealings in products derived from or relating to the Covered Code
     78  1.1.1.19  christos  * without prior written authorization from Intel.
     79  1.1.1.19  christos  *
     80  1.1.1.19  christos  * 4. Disclaimer and Export Compliance
     81  1.1.1.19  christos  *
     82  1.1.1.19  christos  * 4.1. INTEL MAKES NO WARRANTY OF ANY KIND REGARDING ANY SOFTWARE PROVIDED
     83  1.1.1.19  christos  * HERE. ANY SOFTWARE ORIGINATING FROM INTEL OR DERIVED FROM INTEL SOFTWARE
     84  1.1.1.19  christos  * IS PROVIDED "AS IS," AND INTEL WILL NOT PROVIDE ANY SUPPORT, ASSISTANCE,
     85  1.1.1.19  christos  * INSTALLATION, TRAINING OR OTHER SERVICES. INTEL WILL NOT PROVIDE ANY
     86  1.1.1.19  christos  * UPDATES, ENHANCEMENTS OR EXTENSIONS. INTEL SPECIFICALLY DISCLAIMS ANY
     87  1.1.1.19  christos  * IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT AND FITNESS FOR A
     88  1.1.1.19  christos  * PARTICULAR PURPOSE.
     89  1.1.1.19  christos  *
     90  1.1.1.19  christos  * 4.2. IN NO EVENT SHALL INTEL HAVE ANY LIABILITY TO LICENSEE, ITS LICENSEES
     91  1.1.1.19  christos  * OR ANY OTHER THIRD PARTY, FOR ANY LOST PROFITS, LOST DATA, LOSS OF USE OR
     92  1.1.1.19  christos  * COSTS OF PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY INDIRECT,
     93  1.1.1.19  christos  * SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THIS AGREEMENT, UNDER ANY
     94  1.1.1.19  christos  * CAUSE OF ACTION OR THEORY OF LIABILITY, AND IRRESPECTIVE OF WHETHER INTEL
     95  1.1.1.19  christos  * HAS ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. THESE LIMITATIONS
     96  1.1.1.19  christos  * SHALL APPLY NOTWITHSTANDING THE FAILURE OF THE ESSENTIAL PURPOSE OF ANY
     97  1.1.1.19  christos  * LIMITED REMEDY.
     98  1.1.1.19  christos  *
     99  1.1.1.19  christos  * 4.3. Licensee shall not export, either directly or indirectly, any of this
    100  1.1.1.19  christos  * software or system incorporating such software without first obtaining any
    101  1.1.1.19  christos  * required license or other approval from the U. S. Department of Commerce or
    102  1.1.1.19  christos  * any other agency or department of the United States Government. In the
    103  1.1.1.19  christos  * event Licensee exports any such software from the United States or
    104  1.1.1.19  christos  * re-exports any such software from a foreign destination, Licensee shall
    105  1.1.1.19  christos  * ensure that the distribution and export/re-export of the software is in
    106  1.1.1.19  christos  * compliance with all laws, regulations, orders, or other restrictions of the
    107  1.1.1.19  christos  * U.S. Export Administration Regulations. Licensee agrees that neither it nor
    108  1.1.1.19  christos  * any of its subsidiaries will export/re-export any technical data, process,
    109  1.1.1.19  christos  * software, or service, directly or indirectly, to any country for which the
    110  1.1.1.19  christos  * United States government or any agency thereof requires an export license,
    111  1.1.1.19  christos  * other governmental approval, or letter of assurance, without first obtaining
    112  1.1.1.19  christos  * such license, approval or letter.
    113  1.1.1.19  christos  *
    114  1.1.1.19  christos  *****************************************************************************
    115  1.1.1.19  christos  *
    116  1.1.1.19  christos  * Alternatively, you may choose to be licensed under the terms of the
    117  1.1.1.19  christos  * following license:
    118  1.1.1.19  christos  *
    119   1.1.1.2    jruoho  * Redistribution and use in source and binary forms, with or without
    120   1.1.1.2    jruoho  * modification, are permitted provided that the following conditions
    121   1.1.1.2    jruoho  * are met:
    122   1.1.1.2    jruoho  * 1. Redistributions of source code must retain the above copyright
    123   1.1.1.2    jruoho  *    notice, this list of conditions, and the following disclaimer,
    124   1.1.1.2    jruoho  *    without modification.
    125   1.1.1.2    jruoho  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
    126   1.1.1.2    jruoho  *    substantially similar to the "NO WARRANTY" disclaimer below
    127   1.1.1.2    jruoho  *    ("Disclaimer") and any redistribution must be conditioned upon
    128   1.1.1.2    jruoho  *    including a substantially similar Disclaimer requirement for further
    129   1.1.1.2    jruoho  *    binary redistribution.
    130   1.1.1.2    jruoho  * 3. Neither the names of the above-listed copyright holders nor the names
    131   1.1.1.2    jruoho  *    of any contributors may be used to endorse or promote products derived
    132   1.1.1.2    jruoho  *    from this software without specific prior written permission.
    133   1.1.1.2    jruoho  *
    134   1.1.1.2    jruoho  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
    135   1.1.1.2    jruoho  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
    136  1.1.1.16  christos  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
    137   1.1.1.2    jruoho  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
    138  1.1.1.19  christos  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
    139  1.1.1.19  christos  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
    140  1.1.1.19  christos  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
    141  1.1.1.19  christos  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
    142  1.1.1.19  christos  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    143  1.1.1.19  christos  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
    144  1.1.1.19  christos  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    145  1.1.1.19  christos  *
    146  1.1.1.19  christos  * Alternatively, you may choose to be licensed under the terms of the
    147  1.1.1.19  christos  * GNU General Public License ("GPL") version 2 as published by the Free
    148  1.1.1.19  christos  * Software Foundation.
    149  1.1.1.19  christos  *
    150  1.1.1.19  christos  *****************************************************************************/
    151       1.1    jruoho 
    152       1.1    jruoho #include "acpi.h"
    153       1.1    jruoho #include "accommon.h"
    154       1.1    jruoho #include "acdispat.h"
    155       1.1    jruoho #include "acinterp.h"
    156       1.1    jruoho #include "acnamesp.h"
    157   1.1.1.4  christos #include "acparser.h"
    158   1.1.1.4  christos #include "amlcode.h"
    159   1.1.1.6  christos #include "acdebug.h"
    160       1.1    jruoho 
    161       1.1    jruoho 
    162       1.1    jruoho #define _COMPONENT          ACPI_DISPATCHER
    163       1.1    jruoho         ACPI_MODULE_NAME    ("dsmethod")
    164       1.1    jruoho 
    165       1.1    jruoho /* Local prototypes */
    166       1.1    jruoho 
    167       1.1    jruoho static ACPI_STATUS
    168   1.1.1.4  christos AcpiDsDetectNamedOpcodes (
    169   1.1.1.4  christos     ACPI_WALK_STATE         *WalkState,
    170   1.1.1.4  christos     ACPI_PARSE_OBJECT       **OutOp);
    171   1.1.1.4  christos 
    172   1.1.1.4  christos static ACPI_STATUS
    173       1.1    jruoho AcpiDsCreateMethodMutex (
    174       1.1    jruoho     ACPI_OPERAND_OBJECT     *MethodDesc);
    175       1.1    jruoho 
    176       1.1    jruoho 
    177       1.1    jruoho /*******************************************************************************
    178       1.1    jruoho  *
    179   1.1.1.4  christos  * FUNCTION:    AcpiDsAutoSerializeMethod
    180   1.1.1.4  christos  *
    181   1.1.1.4  christos  * PARAMETERS:  Node                        - Namespace Node of the method
    182   1.1.1.4  christos  *              ObjDesc                     - Method object attached to node
    183   1.1.1.4  christos  *
    184   1.1.1.4  christos  * RETURN:      Status
    185   1.1.1.4  christos  *
    186   1.1.1.4  christos  * DESCRIPTION: Parse a control method AML to scan for control methods that
    187   1.1.1.4  christos  *              need serialization due to the creation of named objects.
    188   1.1.1.4  christos  *
    189   1.1.1.4  christos  * NOTE: It is a bit of overkill to mark all such methods serialized, since
    190   1.1.1.4  christos  * there is only a problem if the method actually blocks during execution.
    191   1.1.1.4  christos  * A blocking operation is, for example, a Sleep() operation, or any access
    192   1.1.1.4  christos  * to an operation region. However, it is probably not possible to easily
    193   1.1.1.4  christos  * detect whether a method will block or not, so we simply mark all suspicious
    194   1.1.1.4  christos  * methods as serialized.
    195   1.1.1.4  christos  *
    196   1.1.1.4  christos  * NOTE2: This code is essentially a generic routine for parsing a single
    197   1.1.1.4  christos  * control method.
    198   1.1.1.4  christos  *
    199   1.1.1.4  christos  ******************************************************************************/
    200   1.1.1.4  christos 
    201   1.1.1.4  christos ACPI_STATUS
    202   1.1.1.4  christos AcpiDsAutoSerializeMethod (
    203   1.1.1.4  christos     ACPI_NAMESPACE_NODE     *Node,
    204   1.1.1.4  christos     ACPI_OPERAND_OBJECT     *ObjDesc)
    205   1.1.1.4  christos {
    206   1.1.1.4  christos     ACPI_STATUS             Status;
    207   1.1.1.4  christos     ACPI_PARSE_OBJECT       *Op = NULL;
    208   1.1.1.4  christos     ACPI_WALK_STATE         *WalkState;
    209   1.1.1.4  christos 
    210   1.1.1.4  christos 
    211   1.1.1.4  christos     ACPI_FUNCTION_TRACE_PTR (DsAutoSerializeMethod, Node);
    212   1.1.1.4  christos 
    213   1.1.1.4  christos 
    214   1.1.1.4  christos     ACPI_DEBUG_PRINT ((ACPI_DB_PARSE,
    215   1.1.1.4  christos         "Method auto-serialization parse [%4.4s] %p\n",
    216   1.1.1.4  christos         AcpiUtGetNodeName (Node), Node));
    217   1.1.1.4  christos 
    218   1.1.1.4  christos     /* Create/Init a root op for the method parse tree */
    219   1.1.1.4  christos 
    220   1.1.1.6  christos     Op = AcpiPsAllocOp (AML_METHOD_OP, ObjDesc->Method.AmlStart);
    221   1.1.1.4  christos     if (!Op)
    222   1.1.1.4  christos     {
    223  1.1.1.10  christos         return_ACPI_STATUS (AE_NO_MEMORY);
    224   1.1.1.4  christos     }
    225   1.1.1.4  christos 
    226   1.1.1.4  christos     AcpiPsSetName (Op, Node->Name.Integer);
    227   1.1.1.4  christos     Op->Common.Node = Node;
    228   1.1.1.4  christos 
    229   1.1.1.4  christos     /* Create and initialize a new walk state */
    230   1.1.1.4  christos 
    231   1.1.1.4  christos     WalkState = AcpiDsCreateWalkState (Node->OwnerId, NULL, NULL, NULL);
    232   1.1.1.4  christos     if (!WalkState)
    233   1.1.1.4  christos     {
    234   1.1.1.6  christos         AcpiPsFreeOp (Op);
    235  1.1.1.10  christos         return_ACPI_STATUS (AE_NO_MEMORY);
    236   1.1.1.4  christos     }
    237   1.1.1.4  christos 
    238   1.1.1.7  christos     Status = AcpiDsInitAmlWalk (WalkState, Op, Node,
    239   1.1.1.7  christos         ObjDesc->Method.AmlStart, ObjDesc->Method.AmlLength, NULL, 0);
    240   1.1.1.4  christos     if (ACPI_FAILURE (Status))
    241   1.1.1.4  christos     {
    242   1.1.1.4  christos         AcpiDsDeleteWalkState (WalkState);
    243   1.1.1.6  christos         AcpiPsFreeOp (Op);
    244   1.1.1.4  christos         return_ACPI_STATUS (Status);
    245   1.1.1.4  christos     }
    246   1.1.1.4  christos 
    247   1.1.1.4  christos     WalkState->DescendingCallback = AcpiDsDetectNamedOpcodes;
    248   1.1.1.4  christos 
    249   1.1.1.4  christos     /* Parse the method, scan for creation of named objects */
    250   1.1.1.4  christos 
    251   1.1.1.4  christos     Status = AcpiPsParseAml (WalkState);
    252   1.1.1.4  christos 
    253   1.1.1.4  christos     AcpiPsDeleteParseTree (Op);
    254   1.1.1.4  christos     return_ACPI_STATUS (Status);
    255   1.1.1.4  christos }
    256   1.1.1.4  christos 
    257   1.1.1.4  christos 
    258   1.1.1.4  christos /*******************************************************************************
    259   1.1.1.4  christos  *
    260   1.1.1.4  christos  * FUNCTION:    AcpiDsDetectNamedOpcodes
    261   1.1.1.4  christos  *
    262   1.1.1.4  christos  * PARAMETERS:  WalkState       - Current state of the parse tree walk
    263   1.1.1.4  christos  *              OutOp           - Unused, required for parser interface
    264   1.1.1.4  christos  *
    265   1.1.1.4  christos  * RETURN:      Status
    266   1.1.1.4  christos  *
    267   1.1.1.4  christos  * DESCRIPTION: Descending callback used during the loading of ACPI tables.
    268   1.1.1.4  christos  *              Currently used to detect methods that must be marked serialized
    269   1.1.1.4  christos  *              in order to avoid problems with the creation of named objects.
    270   1.1.1.4  christos  *
    271   1.1.1.4  christos  ******************************************************************************/
    272   1.1.1.4  christos 
    273   1.1.1.4  christos static ACPI_STATUS
    274   1.1.1.4  christos AcpiDsDetectNamedOpcodes (
    275   1.1.1.4  christos     ACPI_WALK_STATE         *WalkState,
    276   1.1.1.4  christos     ACPI_PARSE_OBJECT       **OutOp)
    277   1.1.1.4  christos {
    278   1.1.1.4  christos 
    279   1.1.1.4  christos     ACPI_FUNCTION_NAME (AcpiDsDetectNamedOpcodes);
    280   1.1.1.4  christos 
    281   1.1.1.4  christos 
    282   1.1.1.4  christos     /* We are only interested in opcodes that create a new name */
    283   1.1.1.4  christos 
    284   1.1.1.4  christos     if (!(WalkState->OpInfo->Flags & (AML_NAMED | AML_CREATE | AML_FIELD)))
    285   1.1.1.4  christos     {
    286   1.1.1.4  christos         return (AE_OK);
    287   1.1.1.4  christos     }
    288   1.1.1.4  christos 
    289   1.1.1.4  christos     /*
    290   1.1.1.4  christos      * At this point, we know we have a Named object opcode.
    291   1.1.1.4  christos      * Mark the method as serialized. Later code will create a mutex for
    292   1.1.1.4  christos      * this method to enforce serialization.
    293   1.1.1.4  christos      *
    294   1.1.1.4  christos      * Note, ACPI_METHOD_IGNORE_SYNC_LEVEL flag means that we will ignore the
    295   1.1.1.4  christos      * Sync Level mechanism for this method, even though it is now serialized.
    296   1.1.1.4  christos      * Otherwise, there can be conflicts with existing ASL code that actually
    297   1.1.1.4  christos      * uses sync levels.
    298   1.1.1.4  christos      */
    299   1.1.1.4  christos     WalkState->MethodDesc->Method.SyncLevel = 0;
    300   1.1.1.4  christos     WalkState->MethodDesc->Method.InfoFlags |=
    301   1.1.1.4  christos         (ACPI_METHOD_SERIALIZED | ACPI_METHOD_IGNORE_SYNC_LEVEL);
    302   1.1.1.4  christos 
    303   1.1.1.4  christos     ACPI_DEBUG_PRINT ((ACPI_DB_INFO,
    304   1.1.1.4  christos         "Method serialized [%4.4s] %p - [%s] (%4.4X)\n",
    305   1.1.1.4  christos         WalkState->MethodNode->Name.Ascii, WalkState->MethodNode,
    306   1.1.1.4  christos         WalkState->OpInfo->Name, WalkState->Opcode));
    307   1.1.1.4  christos 
    308   1.1.1.4  christos     /* Abort the parse, no need to examine this method any further */
    309   1.1.1.4  christos 
    310   1.1.1.4  christos     return (AE_CTRL_TERMINATE);
    311   1.1.1.4  christos }
    312   1.1.1.4  christos 
    313   1.1.1.4  christos 
    314   1.1.1.4  christos /*******************************************************************************
    315   1.1.1.4  christos  *
    316       1.1    jruoho  * FUNCTION:    AcpiDsMethodError
    317       1.1    jruoho  *
    318       1.1    jruoho  * PARAMETERS:  Status          - Execution status
    319       1.1    jruoho  *              WalkState       - Current state
    320       1.1    jruoho  *
    321       1.1    jruoho  * RETURN:      Status
    322       1.1    jruoho  *
    323       1.1    jruoho  * DESCRIPTION: Called on method error. Invoke the global exception handler if
    324   1.1.1.6  christos  *              present, dump the method data if the debugger is configured
    325       1.1    jruoho  *
    326       1.1    jruoho  *              Note: Allows the exception handler to change the status code
    327       1.1    jruoho  *
    328       1.1    jruoho  ******************************************************************************/
    329       1.1    jruoho 
    330       1.1    jruoho ACPI_STATUS
    331       1.1    jruoho AcpiDsMethodError (
    332       1.1    jruoho     ACPI_STATUS             Status,
    333       1.1    jruoho     ACPI_WALK_STATE         *WalkState)
    334       1.1    jruoho {
    335   1.1.1.6  christos     UINT32                  AmlOffset;
    336  1.1.1.11  christos     ACPI_NAME               Name = 0;
    337   1.1.1.6  christos 
    338   1.1.1.6  christos 
    339       1.1    jruoho     ACPI_FUNCTION_ENTRY ();
    340       1.1    jruoho 
    341       1.1    jruoho 
    342       1.1    jruoho     /* Ignore AE_OK and control exception codes */
    343       1.1    jruoho 
    344       1.1    jruoho     if (ACPI_SUCCESS (Status) ||
    345       1.1    jruoho         (Status & AE_CODE_CONTROL))
    346       1.1    jruoho     {
    347       1.1    jruoho         return (Status);
    348       1.1    jruoho     }
    349       1.1    jruoho 
    350       1.1    jruoho     /* Invoke the global exception handler */
    351       1.1    jruoho 
    352       1.1    jruoho     if (AcpiGbl_ExceptionHandler)
    353       1.1    jruoho     {
    354       1.1    jruoho         /* Exit the interpreter, allow handler to execute methods */
    355       1.1    jruoho 
    356       1.1    jruoho         AcpiExExitInterpreter ();
    357       1.1    jruoho 
    358       1.1    jruoho         /*
    359       1.1    jruoho          * Handler can map the exception code to anything it wants, including
    360       1.1    jruoho          * AE_OK, in which case the executing method will not be aborted.
    361       1.1    jruoho          */
    362   1.1.1.6  christos         AmlOffset = (UINT32) ACPI_PTR_DIFF (WalkState->Aml,
    363   1.1.1.7  christos             WalkState->ParserState.AmlStart);
    364   1.1.1.6  christos 
    365  1.1.1.11  christos         if (WalkState->MethodNode)
    366  1.1.1.11  christos         {
    367  1.1.1.11  christos             Name = WalkState->MethodNode->Name.Integer;
    368  1.1.1.11  christos         }
    369  1.1.1.11  christos         else if (WalkState->DeferredNode)
    370  1.1.1.11  christos         {
    371  1.1.1.11  christos             Name = WalkState->DeferredNode->Name.Integer;
    372  1.1.1.11  christos         }
    373  1.1.1.11  christos 
    374  1.1.1.11  christos         Status = AcpiGbl_ExceptionHandler (Status, Name,
    375   1.1.1.7  christos             WalkState->Opcode, AmlOffset, NULL);
    376       1.1    jruoho         AcpiExEnterInterpreter ();
    377       1.1    jruoho     }
    378       1.1    jruoho 
    379       1.1    jruoho     AcpiDsClearImplicitReturn (WalkState);
    380       1.1    jruoho 
    381       1.1    jruoho     if (ACPI_FAILURE (Status))
    382       1.1    jruoho     {
    383   1.1.1.6  christos         AcpiDsDumpMethodStack (Status, WalkState, WalkState->Op);
    384       1.1    jruoho 
    385   1.1.1.6  christos         /* Display method locals/args if debugger is present */
    386   1.1.1.6  christos 
    387   1.1.1.6  christos #ifdef ACPI_DEBUGGER
    388   1.1.1.6  christos         AcpiDbDumpMethodInfo (Status, WalkState);
    389       1.1    jruoho #endif
    390   1.1.1.6  christos     }
    391       1.1    jruoho 
    392       1.1    jruoho     return (Status);
    393       1.1    jruoho }
    394       1.1    jruoho 
    395       1.1    jruoho 
    396       1.1    jruoho /*******************************************************************************
    397       1.1    jruoho  *
    398       1.1    jruoho  * FUNCTION:    AcpiDsCreateMethodMutex
    399       1.1    jruoho  *
    400       1.1    jruoho  * PARAMETERS:  ObjDesc             - The method object
    401       1.1    jruoho  *
    402       1.1    jruoho  * RETURN:      Status
    403       1.1    jruoho  *
    404       1.1    jruoho  * DESCRIPTION: Create a mutex object for a serialized control method
    405       1.1    jruoho  *
    406       1.1    jruoho  ******************************************************************************/
    407       1.1    jruoho 
    408       1.1    jruoho static ACPI_STATUS
    409       1.1    jruoho AcpiDsCreateMethodMutex (
    410       1.1    jruoho     ACPI_OPERAND_OBJECT     *MethodDesc)
    411       1.1    jruoho {
    412       1.1    jruoho     ACPI_OPERAND_OBJECT     *MutexDesc;
    413       1.1    jruoho     ACPI_STATUS             Status;
    414       1.1    jruoho 
    415       1.1    jruoho 
    416       1.1    jruoho     ACPI_FUNCTION_TRACE (DsCreateMethodMutex);
    417       1.1    jruoho 
    418       1.1    jruoho 
    419       1.1    jruoho     /* Create the new mutex object */
    420       1.1    jruoho 
    421       1.1    jruoho     MutexDesc = AcpiUtCreateInternalObject (ACPI_TYPE_MUTEX);
    422       1.1    jruoho     if (!MutexDesc)
    423       1.1    jruoho     {
    424       1.1    jruoho         return_ACPI_STATUS (AE_NO_MEMORY);
    425       1.1    jruoho     }
    426       1.1    jruoho 
    427       1.1    jruoho     /* Create the actual OS Mutex */
    428       1.1    jruoho 
    429       1.1    jruoho     Status = AcpiOsCreateMutex (&MutexDesc->Mutex.OsMutex);
    430       1.1    jruoho     if (ACPI_FAILURE (Status))
    431       1.1    jruoho     {
    432   1.1.1.3  christos         AcpiUtDeleteObjectDesc (MutexDesc);
    433       1.1    jruoho         return_ACPI_STATUS (Status);
    434       1.1    jruoho     }
    435       1.1    jruoho 
    436       1.1    jruoho     MutexDesc->Mutex.SyncLevel = MethodDesc->Method.SyncLevel;
    437       1.1    jruoho     MethodDesc->Method.Mutex = MutexDesc;
    438       1.1    jruoho     return_ACPI_STATUS (AE_OK);
    439       1.1    jruoho }
    440       1.1    jruoho 
    441       1.1    jruoho 
    442       1.1    jruoho /*******************************************************************************
    443       1.1    jruoho  *
    444       1.1    jruoho  * FUNCTION:    AcpiDsBeginMethodExecution
    445       1.1    jruoho  *
    446       1.1    jruoho  * PARAMETERS:  MethodNode          - Node of the method
    447       1.1    jruoho  *              ObjDesc             - The method object
    448       1.1    jruoho  *              WalkState           - current state, NULL if not yet executing
    449       1.1    jruoho  *                                    a method.
    450       1.1    jruoho  *
    451       1.1    jruoho  * RETURN:      Status
    452       1.1    jruoho  *
    453   1.1.1.3  christos  * DESCRIPTION: Prepare a method for execution. Parses the method if necessary,
    454       1.1    jruoho  *              increments the thread count, and waits at the method semaphore
    455       1.1    jruoho  *              for clearance to execute.
    456       1.1    jruoho  *
    457       1.1    jruoho  ******************************************************************************/
    458       1.1    jruoho 
    459       1.1    jruoho ACPI_STATUS
    460       1.1    jruoho AcpiDsBeginMethodExecution (
    461       1.1    jruoho     ACPI_NAMESPACE_NODE     *MethodNode,
    462       1.1    jruoho     ACPI_OPERAND_OBJECT     *ObjDesc,
    463       1.1    jruoho     ACPI_WALK_STATE         *WalkState)
    464       1.1    jruoho {
    465       1.1    jruoho     ACPI_STATUS             Status = AE_OK;
    466       1.1    jruoho 
    467       1.1    jruoho 
    468       1.1    jruoho     ACPI_FUNCTION_TRACE_PTR (DsBeginMethodExecution, MethodNode);
    469       1.1    jruoho 
    470       1.1    jruoho 
    471       1.1    jruoho     if (!MethodNode)
    472       1.1    jruoho     {
    473       1.1    jruoho         return_ACPI_STATUS (AE_NULL_ENTRY);
    474       1.1    jruoho     }
    475       1.1    jruoho 
    476   1.1.1.6  christos     AcpiExStartTraceMethod (MethodNode, ObjDesc, WalkState);
    477   1.1.1.6  christos 
    478       1.1    jruoho     /* Prevent wraparound of thread count */
    479       1.1    jruoho 
    480       1.1    jruoho     if (ObjDesc->Method.ThreadCount == ACPI_UINT8_MAX)
    481       1.1    jruoho     {
    482       1.1    jruoho         ACPI_ERROR ((AE_INFO,
    483       1.1    jruoho             "Method reached maximum reentrancy limit (255)"));
    484       1.1    jruoho         return_ACPI_STATUS (AE_AML_METHOD_LIMIT);
    485       1.1    jruoho     }
    486       1.1    jruoho 
    487       1.1    jruoho     /*
    488       1.1    jruoho      * If this method is serialized, we need to acquire the method mutex.
    489       1.1    jruoho      */
    490   1.1.1.2    jruoho     if (ObjDesc->Method.InfoFlags & ACPI_METHOD_SERIALIZED)
    491       1.1    jruoho     {
    492       1.1    jruoho         /*
    493       1.1    jruoho          * Create a mutex for the method if it is defined to be Serialized
    494       1.1    jruoho          * and a mutex has not already been created. We defer the mutex creation
    495       1.1    jruoho          * until a method is actually executed, to minimize the object count
    496       1.1    jruoho          */
    497       1.1    jruoho         if (!ObjDesc->Method.Mutex)
    498       1.1    jruoho         {
    499       1.1    jruoho             Status = AcpiDsCreateMethodMutex (ObjDesc);
    500       1.1    jruoho             if (ACPI_FAILURE (Status))
    501       1.1    jruoho             {
    502       1.1    jruoho                 return_ACPI_STATUS (Status);
    503       1.1    jruoho             }
    504       1.1    jruoho         }
    505       1.1    jruoho 
    506       1.1    jruoho         /*
    507       1.1    jruoho          * The CurrentSyncLevel (per-thread) must be less than or equal to
    508       1.1    jruoho          * the sync level of the method. This mechanism provides some
    509   1.1.1.4  christos          * deadlock prevention.
    510   1.1.1.4  christos          *
    511   1.1.1.4  christos          * If the method was auto-serialized, we just ignore the sync level
    512   1.1.1.4  christos          * mechanism, because auto-serialization of methods can interfere
    513   1.1.1.4  christos          * with ASL code that actually uses sync levels.
    514       1.1    jruoho          *
    515       1.1    jruoho          * Top-level method invocation has no walk state at this point
    516       1.1    jruoho          */
    517       1.1    jruoho         if (WalkState &&
    518   1.1.1.4  christos             (!(ObjDesc->Method.InfoFlags & ACPI_METHOD_IGNORE_SYNC_LEVEL)) &&
    519   1.1.1.7  christos             (WalkState->Thread->CurrentSyncLevel >
    520   1.1.1.7  christos                 ObjDesc->Method.Mutex->Mutex.SyncLevel))
    521       1.1    jruoho         {
    522       1.1    jruoho             ACPI_ERROR ((AE_INFO,
    523   1.1.1.7  christos                 "Cannot acquire Mutex for method [%4.4s]"
    524   1.1.1.7  christos                 ", current SyncLevel is too large (%u)",
    525       1.1    jruoho                 AcpiUtGetNodeName (MethodNode),
    526       1.1    jruoho                 WalkState->Thread->CurrentSyncLevel));
    527       1.1    jruoho 
    528       1.1    jruoho             return_ACPI_STATUS (AE_AML_MUTEX_ORDER);
    529       1.1    jruoho         }
    530       1.1    jruoho 
    531       1.1    jruoho         /*
    532       1.1    jruoho          * Obtain the method mutex if necessary. Do not acquire mutex for a
    533       1.1    jruoho          * recursive call.
    534       1.1    jruoho          */
    535       1.1    jruoho         if (!WalkState ||
    536       1.1    jruoho             !ObjDesc->Method.Mutex->Mutex.ThreadId ||
    537   1.1.1.7  christos             (WalkState->Thread->ThreadId !=
    538   1.1.1.7  christos                 ObjDesc->Method.Mutex->Mutex.ThreadId))
    539       1.1    jruoho         {
    540       1.1    jruoho             /*
    541       1.1    jruoho              * Acquire the method mutex. This releases the interpreter if we
    542       1.1    jruoho              * block (and reacquires it before it returns)
    543       1.1    jruoho              */
    544   1.1.1.7  christos             Status = AcpiExSystemWaitMutex (
    545   1.1.1.7  christos                 ObjDesc->Method.Mutex->Mutex.OsMutex, ACPI_WAIT_FOREVER);
    546       1.1    jruoho             if (ACPI_FAILURE (Status))
    547       1.1    jruoho             {
    548       1.1    jruoho                 return_ACPI_STATUS (Status);
    549       1.1    jruoho             }
    550       1.1    jruoho 
    551       1.1    jruoho             /* Update the mutex and walk info and save the original SyncLevel */
    552       1.1    jruoho 
    553       1.1    jruoho             if (WalkState)
    554       1.1    jruoho             {
    555       1.1    jruoho                 ObjDesc->Method.Mutex->Mutex.OriginalSyncLevel =
    556       1.1    jruoho                     WalkState->Thread->CurrentSyncLevel;
    557       1.1    jruoho 
    558   1.1.1.7  christos                 ObjDesc->Method.Mutex->Mutex.ThreadId =
    559   1.1.1.7  christos                     WalkState->Thread->ThreadId;
    560   1.1.1.7  christos 
    561   1.1.1.7  christos                 /*
    562   1.1.1.7  christos                  * Update the current SyncLevel only if this is not an auto-
    563   1.1.1.7  christos                  * serialized method. In the auto case, we have to ignore
    564   1.1.1.7  christos                  * the sync level for the method mutex (created for the
    565   1.1.1.7  christos                  * auto-serialization) because we have no idea of what the
    566   1.1.1.7  christos                  * sync level should be. Therefore, just ignore it.
    567   1.1.1.7  christos                  */
    568   1.1.1.7  christos                 if (!(ObjDesc->Method.InfoFlags &
    569   1.1.1.7  christos                     ACPI_METHOD_IGNORE_SYNC_LEVEL))
    570   1.1.1.7  christos                 {
    571   1.1.1.7  christos                     WalkState->Thread->CurrentSyncLevel =
    572   1.1.1.7  christos                         ObjDesc->Method.SyncLevel;
    573   1.1.1.7  christos                 }
    574       1.1    jruoho             }
    575       1.1    jruoho             else
    576       1.1    jruoho             {
    577       1.1    jruoho                 ObjDesc->Method.Mutex->Mutex.OriginalSyncLevel =
    578       1.1    jruoho                     ObjDesc->Method.Mutex->Mutex.SyncLevel;
    579   1.1.1.8  christos 
    580   1.1.1.8  christos                 ObjDesc->Method.Mutex->Mutex.ThreadId =
    581   1.1.1.8  christos                     AcpiOsGetThreadId ();
    582       1.1    jruoho             }
    583       1.1    jruoho         }
    584       1.1    jruoho 
    585       1.1    jruoho         /* Always increase acquisition depth */
    586       1.1    jruoho 
    587       1.1    jruoho         ObjDesc->Method.Mutex->Mutex.AcquisitionDepth++;
    588       1.1    jruoho     }
    589       1.1    jruoho 
    590       1.1    jruoho     /*
    591       1.1    jruoho      * Allocate an Owner ID for this method, only if this is the first thread
    592       1.1    jruoho      * to begin concurrent execution. We only need one OwnerId, even if the
    593       1.1    jruoho      * method is invoked recursively.
    594       1.1    jruoho      */
    595       1.1    jruoho     if (!ObjDesc->Method.OwnerId)
    596       1.1    jruoho     {
    597       1.1    jruoho         Status = AcpiUtAllocateOwnerId (&ObjDesc->Method.OwnerId);
    598       1.1    jruoho         if (ACPI_FAILURE (Status))
    599       1.1    jruoho         {
    600       1.1    jruoho             goto Cleanup;
    601       1.1    jruoho         }
    602       1.1    jruoho     }
    603       1.1    jruoho 
    604       1.1    jruoho     /*
    605       1.1    jruoho      * Increment the method parse tree thread count since it has been
    606       1.1    jruoho      * reentered one more time (even if it is the same thread)
    607       1.1    jruoho      */
    608       1.1    jruoho     ObjDesc->Method.ThreadCount++;
    609       1.1    jruoho     AcpiMethodCount++;
    610       1.1    jruoho     return_ACPI_STATUS (Status);
    611       1.1    jruoho 
    612       1.1    jruoho 
    613       1.1    jruoho Cleanup:
    614       1.1    jruoho     /* On error, must release the method mutex (if present) */
    615       1.1    jruoho 
    616       1.1    jruoho     if (ObjDesc->Method.Mutex)
    617       1.1    jruoho     {
    618       1.1    jruoho         AcpiOsReleaseMutex (ObjDesc->Method.Mutex->Mutex.OsMutex);
    619       1.1    jruoho     }
    620       1.1    jruoho     return_ACPI_STATUS (Status);
    621       1.1    jruoho }
    622       1.1    jruoho 
    623       1.1    jruoho 
    624       1.1    jruoho /*******************************************************************************
    625       1.1    jruoho  *
    626       1.1    jruoho  * FUNCTION:    AcpiDsCallControlMethod
    627       1.1    jruoho  *
    628       1.1    jruoho  * PARAMETERS:  Thread              - Info for this thread
    629       1.1    jruoho  *              ThisWalkState       - Current walk state
    630       1.1    jruoho  *              Op                  - Current Op to be walked
    631       1.1    jruoho  *
    632       1.1    jruoho  * RETURN:      Status
    633       1.1    jruoho  *
    634       1.1    jruoho  * DESCRIPTION: Transfer execution to a called control method
    635       1.1    jruoho  *
    636       1.1    jruoho  ******************************************************************************/
    637       1.1    jruoho 
    638       1.1    jruoho ACPI_STATUS
    639       1.1    jruoho AcpiDsCallControlMethod (
    640       1.1    jruoho     ACPI_THREAD_STATE       *Thread,
    641       1.1    jruoho     ACPI_WALK_STATE         *ThisWalkState,
    642       1.1    jruoho     ACPI_PARSE_OBJECT       *Op)
    643       1.1    jruoho {
    644       1.1    jruoho     ACPI_STATUS             Status;
    645       1.1    jruoho     ACPI_NAMESPACE_NODE     *MethodNode;
    646       1.1    jruoho     ACPI_WALK_STATE         *NextWalkState = NULL;
    647       1.1    jruoho     ACPI_OPERAND_OBJECT     *ObjDesc;
    648       1.1    jruoho     ACPI_EVALUATE_INFO      *Info;
    649       1.1    jruoho     UINT32                  i;
    650       1.1    jruoho 
    651       1.1    jruoho 
    652       1.1    jruoho     ACPI_FUNCTION_TRACE_PTR (DsCallControlMethod, ThisWalkState);
    653       1.1    jruoho 
    654   1.1.1.7  christos     ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
    655   1.1.1.7  christos         "Calling method %p, currentstate=%p\n",
    656       1.1    jruoho         ThisWalkState->PrevOp, ThisWalkState));
    657       1.1    jruoho 
    658       1.1    jruoho     /*
    659       1.1    jruoho      * Get the namespace entry for the control method we are about to call
    660       1.1    jruoho      */
    661       1.1    jruoho     MethodNode = ThisWalkState->MethodCallNode;
    662       1.1    jruoho     if (!MethodNode)
    663       1.1    jruoho     {
    664       1.1    jruoho         return_ACPI_STATUS (AE_NULL_ENTRY);
    665       1.1    jruoho     }
    666       1.1    jruoho 
    667       1.1    jruoho     ObjDesc = AcpiNsGetAttachedObject (MethodNode);
    668       1.1    jruoho     if (!ObjDesc)
    669       1.1    jruoho     {
    670       1.1    jruoho         return_ACPI_STATUS (AE_NULL_OBJECT);
    671       1.1    jruoho     }
    672       1.1    jruoho 
    673       1.1    jruoho     /* Init for new method, possibly wait on method mutex */
    674       1.1    jruoho 
    675   1.1.1.7  christos     Status = AcpiDsBeginMethodExecution (
    676   1.1.1.7  christos         MethodNode, ObjDesc, ThisWalkState);
    677       1.1    jruoho     if (ACPI_FAILURE (Status))
    678       1.1    jruoho     {
    679       1.1    jruoho         return_ACPI_STATUS (Status);
    680       1.1    jruoho     }
    681       1.1    jruoho 
    682       1.1    jruoho     /* Begin method parse/execution. Create a new walk state */
    683       1.1    jruoho 
    684   1.1.1.7  christos     NextWalkState = AcpiDsCreateWalkState (
    685   1.1.1.7  christos         ObjDesc->Method.OwnerId, NULL, ObjDesc, Thread);
    686       1.1    jruoho     if (!NextWalkState)
    687       1.1    jruoho     {
    688       1.1    jruoho         Status = AE_NO_MEMORY;
    689       1.1    jruoho         goto Cleanup;
    690       1.1    jruoho     }
    691       1.1    jruoho 
    692       1.1    jruoho     /*
    693       1.1    jruoho      * The resolved arguments were put on the previous walk state's operand
    694       1.1    jruoho      * stack. Operands on the previous walk state stack always
    695       1.1    jruoho      * start at index 0. Also, null terminate the list of arguments
    696       1.1    jruoho      */
    697       1.1    jruoho     ThisWalkState->Operands [ThisWalkState->NumOperands] = NULL;
    698       1.1    jruoho 
    699       1.1    jruoho     /*
    700       1.1    jruoho      * Allocate and initialize the evaluation information block
    701       1.1    jruoho      * TBD: this is somewhat inefficient, should change interface to
    702       1.1    jruoho      * DsInitAmlWalk. For now, keeps this struct off the CPU stack
    703       1.1    jruoho      */
    704       1.1    jruoho     Info = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_EVALUATE_INFO));
    705       1.1    jruoho     if (!Info)
    706       1.1    jruoho     {
    707   1.1.1.3  christos         Status = AE_NO_MEMORY;
    708  1.1.1.18  christos         goto PopWalkState;
    709       1.1    jruoho     }
    710       1.1    jruoho 
    711       1.1    jruoho     Info->Parameters = &ThisWalkState->Operands[0];
    712       1.1    jruoho 
    713       1.1    jruoho     Status = AcpiDsInitAmlWalk (NextWalkState, NULL, MethodNode,
    714   1.1.1.7  christos         ObjDesc->Method.AmlStart, ObjDesc->Method.AmlLength,
    715   1.1.1.7  christos         Info, ACPI_IMODE_EXECUTE);
    716       1.1    jruoho 
    717       1.1    jruoho     ACPI_FREE (Info);
    718       1.1    jruoho     if (ACPI_FAILURE (Status))
    719       1.1    jruoho     {
    720  1.1.1.18  christos         goto PopWalkState;
    721       1.1    jruoho     }
    722       1.1    jruoho 
    723  1.1.1.13  christos     NextWalkState->MethodNestingDepth = ThisWalkState->MethodNestingDepth + 1;
    724  1.1.1.13  christos 
    725       1.1    jruoho     /*
    726       1.1    jruoho      * Delete the operands on the previous walkstate operand stack
    727       1.1    jruoho      * (they were copied to new objects)
    728       1.1    jruoho      */
    729       1.1    jruoho     for (i = 0; i < ObjDesc->Method.ParamCount; i++)
    730       1.1    jruoho     {
    731       1.1    jruoho         AcpiUtRemoveReference (ThisWalkState->Operands [i]);
    732       1.1    jruoho         ThisWalkState->Operands [i] = NULL;
    733       1.1    jruoho     }
    734       1.1    jruoho 
    735       1.1    jruoho     /* Clear the operand stack */
    736       1.1    jruoho 
    737       1.1    jruoho     ThisWalkState->NumOperands = 0;
    738       1.1    jruoho 
    739       1.1    jruoho     ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
    740       1.1    jruoho         "**** Begin nested execution of [%4.4s] **** WalkState=%p\n",
    741       1.1    jruoho         MethodNode->Name.Ascii, NextWalkState));
    742       1.1    jruoho 
    743  1.1.1.13  christos     ThisWalkState->MethodPathname = AcpiNsGetNormalizedPathname (MethodNode, TRUE);
    744  1.1.1.13  christos     ThisWalkState->MethodIsNested = TRUE;
    745  1.1.1.13  christos 
    746  1.1.1.13  christos     /* Optional object evaluation log */
    747  1.1.1.13  christos 
    748  1.1.1.13  christos     ACPI_DEBUG_PRINT_RAW ((ACPI_DB_EVALUATION,
    749  1.1.1.13  christos         "%-26s:  %*s%s\n", "   Nested method call",
    750  1.1.1.13  christos         NextWalkState->MethodNestingDepth * 3, " ",
    751  1.1.1.13  christos         &ThisWalkState->MethodPathname[1]));
    752  1.1.1.13  christos 
    753       1.1    jruoho     /* Invoke an internal method if necessary */
    754       1.1    jruoho 
    755   1.1.1.2    jruoho     if (ObjDesc->Method.InfoFlags & ACPI_METHOD_INTERNAL_ONLY)
    756       1.1    jruoho     {
    757   1.1.1.2    jruoho         Status = ObjDesc->Method.Dispatch.Implementation (NextWalkState);
    758       1.1    jruoho         if (Status == AE_OK)
    759       1.1    jruoho         {
    760       1.1    jruoho             Status = AE_CTRL_TERMINATE;
    761       1.1    jruoho         }
    762       1.1    jruoho     }
    763       1.1    jruoho 
    764       1.1    jruoho     return_ACPI_STATUS (Status);
    765       1.1    jruoho 
    766       1.1    jruoho 
    767  1.1.1.18  christos PopWalkState:
    768  1.1.1.18  christos 
    769  1.1.1.18  christos     /* On error, pop the walk state to be deleted from thread */
    770  1.1.1.18  christos 
    771  1.1.1.18  christos     AcpiDsPopWalkState(Thread);
    772  1.1.1.18  christos 
    773       1.1    jruoho Cleanup:
    774       1.1    jruoho 
    775       1.1    jruoho     /* On error, we must terminate the method properly */
    776       1.1    jruoho 
    777       1.1    jruoho     AcpiDsTerminateControlMethod (ObjDesc, NextWalkState);
    778   1.1.1.6  christos     AcpiDsDeleteWalkState (NextWalkState);
    779       1.1    jruoho 
    780       1.1    jruoho     return_ACPI_STATUS (Status);
    781       1.1    jruoho }
    782       1.1    jruoho 
    783       1.1    jruoho 
    784       1.1    jruoho /*******************************************************************************
    785       1.1    jruoho  *
    786       1.1    jruoho  * FUNCTION:    AcpiDsRestartControlMethod
    787       1.1    jruoho  *
    788       1.1    jruoho  * PARAMETERS:  WalkState           - State for preempted method (caller)
    789       1.1    jruoho  *              ReturnDesc          - Return value from the called method
    790       1.1    jruoho  *
    791       1.1    jruoho  * RETURN:      Status
    792       1.1    jruoho  *
    793       1.1    jruoho  * DESCRIPTION: Restart a method that was preempted by another (nested) method
    794   1.1.1.3  christos  *              invocation. Handle the return value (if any) from the callee.
    795       1.1    jruoho  *
    796       1.1    jruoho  ******************************************************************************/
    797       1.1    jruoho 
    798       1.1    jruoho ACPI_STATUS
    799       1.1    jruoho AcpiDsRestartControlMethod (
    800       1.1    jruoho     ACPI_WALK_STATE         *WalkState,
    801       1.1    jruoho     ACPI_OPERAND_OBJECT     *ReturnDesc)
    802       1.1    jruoho {
    803       1.1    jruoho     ACPI_STATUS             Status;
    804       1.1    jruoho     int                     SameAsImplicitReturn;
    805       1.1    jruoho 
    806       1.1    jruoho 
    807       1.1    jruoho     ACPI_FUNCTION_TRACE_PTR (DsRestartControlMethod, WalkState);
    808       1.1    jruoho 
    809       1.1    jruoho 
    810       1.1    jruoho     ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
    811       1.1    jruoho         "****Restart [%4.4s] Op %p ReturnValueFromCallee %p\n",
    812       1.1    jruoho         AcpiUtGetNodeName (WalkState->MethodNode),
    813       1.1    jruoho         WalkState->MethodCallOp, ReturnDesc));
    814       1.1    jruoho 
    815       1.1    jruoho     ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
    816       1.1    jruoho         "    ReturnFromThisMethodUsed?=%X ResStack %p Walk %p\n",
    817       1.1    jruoho         WalkState->ReturnUsed,
    818       1.1    jruoho         WalkState->Results, WalkState));
    819       1.1    jruoho 
    820       1.1    jruoho     /* Did the called method return a value? */
    821       1.1    jruoho 
    822       1.1    jruoho     if (ReturnDesc)
    823       1.1    jruoho     {
    824       1.1    jruoho         /* Is the implicit return object the same as the return desc? */
    825       1.1    jruoho 
    826       1.1    jruoho         SameAsImplicitReturn = (WalkState->ImplicitReturnObj == ReturnDesc);
    827       1.1    jruoho 
    828       1.1    jruoho         /* Are we actually going to use the return value? */
    829       1.1    jruoho 
    830       1.1    jruoho         if (WalkState->ReturnUsed)
    831       1.1    jruoho         {
    832       1.1    jruoho             /* Save the return value from the previous method */
    833       1.1    jruoho 
    834       1.1    jruoho             Status = AcpiDsResultPush (ReturnDesc, WalkState);
    835       1.1    jruoho             if (ACPI_FAILURE (Status))
    836       1.1    jruoho             {
    837       1.1    jruoho                 AcpiUtRemoveReference (ReturnDesc);
    838       1.1    jruoho                 return_ACPI_STATUS (Status);
    839       1.1    jruoho             }
    840       1.1    jruoho 
    841       1.1    jruoho             /*
    842       1.1    jruoho              * Save as THIS method's return value in case it is returned
    843       1.1    jruoho              * immediately to yet another method
    844       1.1    jruoho              */
    845       1.1    jruoho             WalkState->ReturnDesc = ReturnDesc;
    846       1.1    jruoho         }
    847       1.1    jruoho 
    848       1.1    jruoho         /*
    849       1.1    jruoho          * The following code is the optional support for the so-called
    850       1.1    jruoho          * "implicit return". Some AML code assumes that the last value of the
    851       1.1    jruoho          * method is "implicitly" returned to the caller, in the absence of an
    852       1.1    jruoho          * explicit return value.
    853       1.1    jruoho          *
    854       1.1    jruoho          * Just save the last result of the method as the return value.
    855       1.1    jruoho          *
    856       1.1    jruoho          * NOTE: this is optional because the ASL language does not actually
    857       1.1    jruoho          * support this behavior.
    858       1.1    jruoho          */
    859       1.1    jruoho         else if (!AcpiDsDoImplicitReturn (ReturnDesc, WalkState, FALSE) ||
    860       1.1    jruoho                  SameAsImplicitReturn)
    861       1.1    jruoho         {
    862       1.1    jruoho             /*
    863       1.1    jruoho              * Delete the return value if it will not be used by the
    864       1.1    jruoho              * calling method or remove one reference if the explicit return
    865       1.1    jruoho              * is the same as the implicit return value.
    866       1.1    jruoho              */
    867       1.1    jruoho             AcpiUtRemoveReference (ReturnDesc);
    868       1.1    jruoho         }
    869       1.1    jruoho     }
    870       1.1    jruoho 
    871       1.1    jruoho     return_ACPI_STATUS (AE_OK);
    872       1.1    jruoho }
    873       1.1    jruoho 
    874       1.1    jruoho 
    875       1.1    jruoho /*******************************************************************************
    876       1.1    jruoho  *
    877       1.1    jruoho  * FUNCTION:    AcpiDsTerminateControlMethod
    878       1.1    jruoho  *
    879       1.1    jruoho  * PARAMETERS:  MethodDesc          - Method object
    880       1.1    jruoho  *              WalkState           - State associated with the method
    881       1.1    jruoho  *
    882       1.1    jruoho  * RETURN:      None
    883       1.1    jruoho  *
    884   1.1.1.3  christos  * DESCRIPTION: Terminate a control method. Delete everything that the method
    885       1.1    jruoho  *              created, delete all locals and arguments, and delete the parse
    886       1.1    jruoho  *              tree if requested.
    887       1.1    jruoho  *
    888       1.1    jruoho  * MUTEX:       Interpreter is locked
    889       1.1    jruoho  *
    890       1.1    jruoho  ******************************************************************************/
    891       1.1    jruoho 
    892       1.1    jruoho void
    893       1.1    jruoho AcpiDsTerminateControlMethod (
    894       1.1    jruoho     ACPI_OPERAND_OBJECT     *MethodDesc,
    895       1.1    jruoho     ACPI_WALK_STATE         *WalkState)
    896       1.1    jruoho {
    897       1.1    jruoho 
    898       1.1    jruoho     ACPI_FUNCTION_TRACE_PTR (DsTerminateControlMethod, WalkState);
    899       1.1    jruoho 
    900       1.1    jruoho 
    901       1.1    jruoho     /* MethodDesc is required, WalkState is optional */
    902       1.1    jruoho 
    903       1.1    jruoho     if (!MethodDesc)
    904       1.1    jruoho     {
    905       1.1    jruoho         return_VOID;
    906       1.1    jruoho     }
    907       1.1    jruoho 
    908       1.1    jruoho     if (WalkState)
    909       1.1    jruoho     {
    910       1.1    jruoho         /* Delete all arguments and locals */
    911       1.1    jruoho 
    912       1.1    jruoho         AcpiDsMethodDataDeleteAll (WalkState);
    913       1.1    jruoho 
    914       1.1    jruoho         /*
    915       1.1    jruoho          * Delete any namespace objects created anywhere within the
    916   1.1.1.2    jruoho          * namespace by the execution of this method. Unless:
    917   1.1.1.2    jruoho          * 1) This method is a module-level executable code method, in which
    918   1.1.1.2    jruoho          *    case we want make the objects permanent.
    919   1.1.1.2    jruoho          * 2) There are other threads executing the method, in which case we
    920   1.1.1.2    jruoho          *    will wait until the last thread has completed.
    921       1.1    jruoho          */
    922   1.1.1.2    jruoho         if (!(MethodDesc->Method.InfoFlags & ACPI_METHOD_MODULE_LEVEL) &&
    923   1.1.1.2    jruoho              (MethodDesc->Method.ThreadCount == 1))
    924       1.1    jruoho         {
    925       1.1    jruoho             /* Delete any direct children of (created by) this method */
    926       1.1    jruoho 
    927   1.1.1.9  christos             (void) AcpiExExitInterpreter ();
    928       1.1    jruoho             AcpiNsDeleteNamespaceSubtree (WalkState->MethodNode);
    929   1.1.1.9  christos             (void) AcpiExEnterInterpreter ();
    930       1.1    jruoho 
    931       1.1    jruoho             /*
    932       1.1    jruoho              * Delete any objects that were created by this method
    933       1.1    jruoho              * elsewhere in the namespace (if any were created).
    934   1.1.1.2    jruoho              * Use of the ACPI_METHOD_MODIFIED_NAMESPACE optimizes the
    935   1.1.1.2    jruoho              * deletion such that we don't have to perform an entire
    936   1.1.1.2    jruoho              * namespace walk for every control method execution.
    937       1.1    jruoho              */
    938   1.1.1.2    jruoho             if (MethodDesc->Method.InfoFlags & ACPI_METHOD_MODIFIED_NAMESPACE)
    939       1.1    jruoho             {
    940   1.1.1.9  christos                 (void) AcpiExExitInterpreter ();
    941       1.1    jruoho                 AcpiNsDeleteNamespaceByOwner (MethodDesc->Method.OwnerId);
    942   1.1.1.9  christos                 (void) AcpiExEnterInterpreter ();
    943   1.1.1.7  christos                 MethodDesc->Method.InfoFlags &=
    944   1.1.1.7  christos                     ~ACPI_METHOD_MODIFIED_NAMESPACE;
    945       1.1    jruoho             }
    946       1.1    jruoho         }
    947  1.1.1.10  christos 
    948  1.1.1.10  christos         /*
    949  1.1.1.10  christos          * If method is serialized, release the mutex and restore the
    950  1.1.1.10  christos          * current sync level for this thread
    951  1.1.1.10  christos          */
    952  1.1.1.10  christos         if (MethodDesc->Method.Mutex)
    953  1.1.1.10  christos         {
    954  1.1.1.10  christos             /* Acquisition Depth handles recursive calls */
    955  1.1.1.10  christos 
    956  1.1.1.10  christos             MethodDesc->Method.Mutex->Mutex.AcquisitionDepth--;
    957  1.1.1.10  christos             if (!MethodDesc->Method.Mutex->Mutex.AcquisitionDepth)
    958  1.1.1.10  christos             {
    959  1.1.1.10  christos                 WalkState->Thread->CurrentSyncLevel =
    960  1.1.1.10  christos                     MethodDesc->Method.Mutex->Mutex.OriginalSyncLevel;
    961  1.1.1.10  christos 
    962  1.1.1.10  christos                 AcpiOsReleaseMutex (
    963  1.1.1.10  christos                     MethodDesc->Method.Mutex->Mutex.OsMutex);
    964  1.1.1.10  christos                 MethodDesc->Method.Mutex->Mutex.ThreadId = 0;
    965  1.1.1.10  christos             }
    966  1.1.1.10  christos         }
    967       1.1    jruoho     }
    968       1.1    jruoho 
    969       1.1    jruoho     /* Decrement the thread count on the method */
    970       1.1    jruoho 
    971       1.1    jruoho     if (MethodDesc->Method.ThreadCount)
    972       1.1    jruoho     {
    973       1.1    jruoho         MethodDesc->Method.ThreadCount--;
    974       1.1    jruoho     }
    975       1.1    jruoho     else
    976       1.1    jruoho     {
    977       1.1    jruoho         ACPI_ERROR ((AE_INFO,
    978       1.1    jruoho             "Invalid zero thread count in method"));
    979       1.1    jruoho     }
    980       1.1    jruoho 
    981       1.1    jruoho     /* Are there any other threads currently executing this method? */
    982       1.1    jruoho 
    983       1.1    jruoho     if (MethodDesc->Method.ThreadCount)
    984       1.1    jruoho     {
    985       1.1    jruoho         /*
    986       1.1    jruoho          * Additional threads. Do not release the OwnerId in this case,
    987       1.1    jruoho          * we immediately reuse it for the next thread executing this method
    988       1.1    jruoho          */
    989       1.1    jruoho         ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
    990       1.1    jruoho             "*** Completed execution of one thread, %u threads remaining\n",
    991       1.1    jruoho             MethodDesc->Method.ThreadCount));
    992       1.1    jruoho     }
    993       1.1    jruoho     else
    994       1.1    jruoho     {
    995       1.1    jruoho         /* This is the only executing thread for this method */
    996       1.1    jruoho 
    997       1.1    jruoho         /*
    998       1.1    jruoho          * Support to dynamically change a method from NotSerialized to
    999       1.1    jruoho          * Serialized if it appears that the method is incorrectly written and
   1000       1.1    jruoho          * does not support multiple thread execution. The best example of this
   1001       1.1    jruoho          * is if such a method creates namespace objects and blocks. A second
   1002   1.1.1.2    jruoho          * thread will fail with an AE_ALREADY_EXISTS exception.
   1003       1.1    jruoho          *
   1004       1.1    jruoho          * This code is here because we must wait until the last thread exits
   1005   1.1.1.2    jruoho          * before marking the method as serialized.
   1006       1.1    jruoho          */
   1007   1.1.1.2    jruoho         if (MethodDesc->Method.InfoFlags & ACPI_METHOD_SERIALIZED_PENDING)
   1008       1.1    jruoho         {
   1009   1.1.1.2    jruoho             if (WalkState)
   1010   1.1.1.2    jruoho             {
   1011   1.1.1.8  christos                 ACPI_INFO ((
   1012   1.1.1.7  christos                     "Marking method %4.4s as Serialized "
   1013   1.1.1.7  christos                     "because of AE_ALREADY_EXISTS error",
   1014   1.1.1.2    jruoho                     WalkState->MethodNode->Name.Ascii));
   1015   1.1.1.2    jruoho             }
   1016   1.1.1.2    jruoho 
   1017   1.1.1.2    jruoho             /*
   1018   1.1.1.2    jruoho              * Method tried to create an object twice and was marked as
   1019   1.1.1.2    jruoho              * "pending serialized". The probable cause is that the method
   1020   1.1.1.2    jruoho              * cannot handle reentrancy.
   1021   1.1.1.2    jruoho              *
   1022   1.1.1.2    jruoho              * The method was created as NotSerialized, but it tried to create
   1023   1.1.1.2    jruoho              * a named object and then blocked, causing the second thread
   1024   1.1.1.2    jruoho              * entrance to begin and then fail. Workaround this problem by
   1025   1.1.1.2    jruoho              * marking the method permanently as Serialized when the last
   1026   1.1.1.2    jruoho              * thread exits here.
   1027   1.1.1.2    jruoho              */
   1028   1.1.1.7  christos             MethodDesc->Method.InfoFlags &=
   1029   1.1.1.7  christos                 ~ACPI_METHOD_SERIALIZED_PENDING;
   1030   1.1.1.7  christos 
   1031   1.1.1.4  christos             MethodDesc->Method.InfoFlags |=
   1032   1.1.1.4  christos                 (ACPI_METHOD_SERIALIZED | ACPI_METHOD_IGNORE_SYNC_LEVEL);
   1033   1.1.1.2    jruoho             MethodDesc->Method.SyncLevel = 0;
   1034       1.1    jruoho         }
   1035       1.1    jruoho 
   1036       1.1    jruoho         /* No more threads, we can free the OwnerId */
   1037       1.1    jruoho 
   1038   1.1.1.2    jruoho         if (!(MethodDesc->Method.InfoFlags & ACPI_METHOD_MODULE_LEVEL))
   1039       1.1    jruoho         {
   1040       1.1    jruoho             AcpiUtReleaseOwnerId (&MethodDesc->Method.OwnerId);
   1041       1.1    jruoho         }
   1042       1.1    jruoho     }
   1043       1.1    jruoho 
   1044   1.1.1.6  christos     AcpiExStopTraceMethod ((ACPI_NAMESPACE_NODE *) MethodDesc->Method.Node,
   1045   1.1.1.7  christos         MethodDesc, WalkState);
   1046   1.1.1.6  christos 
   1047       1.1    jruoho     return_VOID;
   1048       1.1    jruoho }
   1049