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