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