The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/contrib/dev/acpica/components/dispatcher/dsmethod.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: 6d06e47613bd6d84728b256131e159a5


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.