1433d6423SLionel Sambuc /******************************************************************************
2433d6423SLionel Sambuc *
3433d6423SLionel Sambuc * Module Name: dsmethod - Parser/Interpreter interface - control method parsing
4433d6423SLionel Sambuc *
5433d6423SLionel Sambuc *****************************************************************************/
6433d6423SLionel Sambuc
7*29492bb7SDavid van Moolenbroek /*
8*29492bb7SDavid van Moolenbroek * Copyright (C) 2000 - 2014, Intel Corp.
9433d6423SLionel Sambuc * All rights reserved.
10433d6423SLionel Sambuc *
11*29492bb7SDavid van Moolenbroek * Redistribution and use in source and binary forms, with or without
12*29492bb7SDavid van Moolenbroek * modification, are permitted provided that the following conditions
13*29492bb7SDavid van Moolenbroek * are met:
14*29492bb7SDavid van Moolenbroek * 1. Redistributions of source code must retain the above copyright
15*29492bb7SDavid van Moolenbroek * notice, this list of conditions, and the following disclaimer,
16*29492bb7SDavid van Moolenbroek * without modification.
17*29492bb7SDavid van Moolenbroek * 2. Redistributions in binary form must reproduce at minimum a disclaimer
18*29492bb7SDavid van Moolenbroek * substantially similar to the "NO WARRANTY" disclaimer below
19*29492bb7SDavid van Moolenbroek * ("Disclaimer") and any redistribution must be conditioned upon
20*29492bb7SDavid van Moolenbroek * including a substantially similar Disclaimer requirement for further
21*29492bb7SDavid van Moolenbroek * binary redistribution.
22*29492bb7SDavid van Moolenbroek * 3. Neither the names of the above-listed copyright holders nor the names
23*29492bb7SDavid van Moolenbroek * of any contributors may be used to endorse or promote products derived
24*29492bb7SDavid van Moolenbroek * from this software without specific prior written permission.
25433d6423SLionel Sambuc *
26*29492bb7SDavid van Moolenbroek * Alternatively, this software may be distributed under the terms of the
27*29492bb7SDavid van Moolenbroek * GNU General Public License ("GPL") version 2 as published by the Free
28*29492bb7SDavid van Moolenbroek * Software Foundation.
29433d6423SLionel Sambuc *
30*29492bb7SDavid van Moolenbroek * NO WARRANTY
31*29492bb7SDavid van Moolenbroek * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32*29492bb7SDavid van Moolenbroek * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33*29492bb7SDavid van Moolenbroek * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
34*29492bb7SDavid van Moolenbroek * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
35*29492bb7SDavid van Moolenbroek * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36*29492bb7SDavid van Moolenbroek * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37*29492bb7SDavid van Moolenbroek * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38*29492bb7SDavid van Moolenbroek * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39*29492bb7SDavid van Moolenbroek * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
40*29492bb7SDavid van Moolenbroek * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41*29492bb7SDavid van Moolenbroek * POSSIBILITY OF SUCH DAMAGES.
42*29492bb7SDavid van Moolenbroek */
43433d6423SLionel Sambuc
44433d6423SLionel Sambuc #include "acpi.h"
45433d6423SLionel Sambuc #include "accommon.h"
46433d6423SLionel Sambuc #include "acdispat.h"
47433d6423SLionel Sambuc #include "acinterp.h"
48433d6423SLionel Sambuc #include "acnamesp.h"
49433d6423SLionel Sambuc #include "acdisasm.h"
50*29492bb7SDavid van Moolenbroek #include "acparser.h"
51*29492bb7SDavid van Moolenbroek #include "amlcode.h"
52433d6423SLionel Sambuc
53433d6423SLionel Sambuc
54433d6423SLionel Sambuc #define _COMPONENT ACPI_DISPATCHER
55433d6423SLionel Sambuc ACPI_MODULE_NAME ("dsmethod")
56433d6423SLionel Sambuc
57433d6423SLionel Sambuc /* Local prototypes */
58433d6423SLionel Sambuc
59433d6423SLionel Sambuc static ACPI_STATUS
60*29492bb7SDavid van Moolenbroek AcpiDsDetectNamedOpcodes (
61*29492bb7SDavid van Moolenbroek ACPI_WALK_STATE *WalkState,
62*29492bb7SDavid van Moolenbroek ACPI_PARSE_OBJECT **OutOp);
63*29492bb7SDavid van Moolenbroek
64*29492bb7SDavid van Moolenbroek static ACPI_STATUS
65433d6423SLionel Sambuc AcpiDsCreateMethodMutex (
66433d6423SLionel Sambuc ACPI_OPERAND_OBJECT *MethodDesc);
67433d6423SLionel Sambuc
68433d6423SLionel Sambuc
69433d6423SLionel Sambuc /*******************************************************************************
70433d6423SLionel Sambuc *
71*29492bb7SDavid van Moolenbroek * FUNCTION: AcpiDsAutoSerializeMethod
72*29492bb7SDavid van Moolenbroek *
73*29492bb7SDavid van Moolenbroek * PARAMETERS: Node - Namespace Node of the method
74*29492bb7SDavid van Moolenbroek * ObjDesc - Method object attached to node
75*29492bb7SDavid van Moolenbroek *
76*29492bb7SDavid van Moolenbroek * RETURN: Status
77*29492bb7SDavid van Moolenbroek *
78*29492bb7SDavid van Moolenbroek * DESCRIPTION: Parse a control method AML to scan for control methods that
79*29492bb7SDavid van Moolenbroek * need serialization due to the creation of named objects.
80*29492bb7SDavid van Moolenbroek *
81*29492bb7SDavid van Moolenbroek * NOTE: It is a bit of overkill to mark all such methods serialized, since
82*29492bb7SDavid van Moolenbroek * there is only a problem if the method actually blocks during execution.
83*29492bb7SDavid van Moolenbroek * A blocking operation is, for example, a Sleep() operation, or any access
84*29492bb7SDavid van Moolenbroek * to an operation region. However, it is probably not possible to easily
85*29492bb7SDavid van Moolenbroek * detect whether a method will block or not, so we simply mark all suspicious
86*29492bb7SDavid van Moolenbroek * methods as serialized.
87*29492bb7SDavid van Moolenbroek *
88*29492bb7SDavid van Moolenbroek * NOTE2: This code is essentially a generic routine for parsing a single
89*29492bb7SDavid van Moolenbroek * control method.
90*29492bb7SDavid van Moolenbroek *
91*29492bb7SDavid van Moolenbroek ******************************************************************************/
92*29492bb7SDavid van Moolenbroek
93*29492bb7SDavid van Moolenbroek ACPI_STATUS
AcpiDsAutoSerializeMethod(ACPI_NAMESPACE_NODE * Node,ACPI_OPERAND_OBJECT * ObjDesc)94*29492bb7SDavid van Moolenbroek AcpiDsAutoSerializeMethod (
95*29492bb7SDavid van Moolenbroek ACPI_NAMESPACE_NODE *Node,
96*29492bb7SDavid van Moolenbroek ACPI_OPERAND_OBJECT *ObjDesc)
97*29492bb7SDavid van Moolenbroek {
98*29492bb7SDavid van Moolenbroek ACPI_STATUS Status;
99*29492bb7SDavid van Moolenbroek ACPI_PARSE_OBJECT *Op = NULL;
100*29492bb7SDavid van Moolenbroek ACPI_WALK_STATE *WalkState;
101*29492bb7SDavid van Moolenbroek
102*29492bb7SDavid van Moolenbroek
103*29492bb7SDavid van Moolenbroek ACPI_FUNCTION_TRACE_PTR (DsAutoSerializeMethod, Node);
104*29492bb7SDavid van Moolenbroek
105*29492bb7SDavid van Moolenbroek
106*29492bb7SDavid van Moolenbroek ACPI_DEBUG_PRINT ((ACPI_DB_PARSE,
107*29492bb7SDavid van Moolenbroek "Method auto-serialization parse [%4.4s] %p\n",
108*29492bb7SDavid van Moolenbroek AcpiUtGetNodeName (Node), Node));
109*29492bb7SDavid van Moolenbroek
110*29492bb7SDavid van Moolenbroek /* Create/Init a root op for the method parse tree */
111*29492bb7SDavid van Moolenbroek
112*29492bb7SDavid van Moolenbroek Op = AcpiPsAllocOp (AML_METHOD_OP);
113*29492bb7SDavid van Moolenbroek if (!Op)
114*29492bb7SDavid van Moolenbroek {
115*29492bb7SDavid van Moolenbroek return_ACPI_STATUS (AE_NO_MEMORY);
116*29492bb7SDavid van Moolenbroek }
117*29492bb7SDavid van Moolenbroek
118*29492bb7SDavid van Moolenbroek AcpiPsSetName (Op, Node->Name.Integer);
119*29492bb7SDavid van Moolenbroek Op->Common.Node = Node;
120*29492bb7SDavid van Moolenbroek
121*29492bb7SDavid van Moolenbroek /* Create and initialize a new walk state */
122*29492bb7SDavid van Moolenbroek
123*29492bb7SDavid van Moolenbroek WalkState = AcpiDsCreateWalkState (Node->OwnerId, NULL, NULL, NULL);
124*29492bb7SDavid van Moolenbroek if (!WalkState)
125*29492bb7SDavid van Moolenbroek {
126*29492bb7SDavid van Moolenbroek return_ACPI_STATUS (AE_NO_MEMORY);
127*29492bb7SDavid van Moolenbroek }
128*29492bb7SDavid van Moolenbroek
129*29492bb7SDavid van Moolenbroek Status = AcpiDsInitAmlWalk (WalkState, Op, Node, ObjDesc->Method.AmlStart,
130*29492bb7SDavid van Moolenbroek ObjDesc->Method.AmlLength, NULL, 0);
131*29492bb7SDavid van Moolenbroek if (ACPI_FAILURE (Status))
132*29492bb7SDavid van Moolenbroek {
133*29492bb7SDavid van Moolenbroek AcpiDsDeleteWalkState (WalkState);
134*29492bb7SDavid van Moolenbroek return_ACPI_STATUS (Status);
135*29492bb7SDavid van Moolenbroek }
136*29492bb7SDavid van Moolenbroek
137*29492bb7SDavid van Moolenbroek WalkState->DescendingCallback = AcpiDsDetectNamedOpcodes;
138*29492bb7SDavid van Moolenbroek
139*29492bb7SDavid van Moolenbroek /* Parse the method, scan for creation of named objects */
140*29492bb7SDavid van Moolenbroek
141*29492bb7SDavid van Moolenbroek Status = AcpiPsParseAml (WalkState);
142*29492bb7SDavid van Moolenbroek if (ACPI_FAILURE (Status))
143*29492bb7SDavid van Moolenbroek {
144*29492bb7SDavid van Moolenbroek return_ACPI_STATUS (Status);
145*29492bb7SDavid van Moolenbroek }
146*29492bb7SDavid van Moolenbroek
147*29492bb7SDavid van Moolenbroek AcpiPsDeleteParseTree (Op);
148*29492bb7SDavid van Moolenbroek return_ACPI_STATUS (Status);
149*29492bb7SDavid van Moolenbroek }
150*29492bb7SDavid van Moolenbroek
151*29492bb7SDavid van Moolenbroek
152*29492bb7SDavid van Moolenbroek /*******************************************************************************
153*29492bb7SDavid van Moolenbroek *
154*29492bb7SDavid van Moolenbroek * FUNCTION: AcpiDsDetectNamedOpcodes
155*29492bb7SDavid van Moolenbroek *
156*29492bb7SDavid van Moolenbroek * PARAMETERS: WalkState - Current state of the parse tree walk
157*29492bb7SDavid van Moolenbroek * OutOp - Unused, required for parser interface
158*29492bb7SDavid van Moolenbroek *
159*29492bb7SDavid van Moolenbroek * RETURN: Status
160*29492bb7SDavid van Moolenbroek *
161*29492bb7SDavid van Moolenbroek * DESCRIPTION: Descending callback used during the loading of ACPI tables.
162*29492bb7SDavid van Moolenbroek * Currently used to detect methods that must be marked serialized
163*29492bb7SDavid van Moolenbroek * in order to avoid problems with the creation of named objects.
164*29492bb7SDavid van Moolenbroek *
165*29492bb7SDavid van Moolenbroek ******************************************************************************/
166*29492bb7SDavid van Moolenbroek
167*29492bb7SDavid van Moolenbroek static ACPI_STATUS
AcpiDsDetectNamedOpcodes(ACPI_WALK_STATE * WalkState,ACPI_PARSE_OBJECT ** OutOp)168*29492bb7SDavid van Moolenbroek AcpiDsDetectNamedOpcodes (
169*29492bb7SDavid van Moolenbroek ACPI_WALK_STATE *WalkState,
170*29492bb7SDavid van Moolenbroek ACPI_PARSE_OBJECT **OutOp)
171*29492bb7SDavid van Moolenbroek {
172*29492bb7SDavid van Moolenbroek
173*29492bb7SDavid van Moolenbroek ACPI_FUNCTION_NAME (AcpiDsDetectNamedOpcodes);
174*29492bb7SDavid van Moolenbroek
175*29492bb7SDavid van Moolenbroek
176*29492bb7SDavid van Moolenbroek /* We are only interested in opcodes that create a new name */
177*29492bb7SDavid van Moolenbroek
178*29492bb7SDavid van Moolenbroek if (!(WalkState->OpInfo->Flags & (AML_NAMED | AML_CREATE | AML_FIELD)))
179*29492bb7SDavid van Moolenbroek {
180*29492bb7SDavid van Moolenbroek return (AE_OK);
181*29492bb7SDavid van Moolenbroek }
182*29492bb7SDavid van Moolenbroek
183*29492bb7SDavid van Moolenbroek /*
184*29492bb7SDavid van Moolenbroek * At this point, we know we have a Named object opcode.
185*29492bb7SDavid van Moolenbroek * Mark the method as serialized. Later code will create a mutex for
186*29492bb7SDavid van Moolenbroek * this method to enforce serialization.
187*29492bb7SDavid van Moolenbroek *
188*29492bb7SDavid van Moolenbroek * Note, ACPI_METHOD_IGNORE_SYNC_LEVEL flag means that we will ignore the
189*29492bb7SDavid van Moolenbroek * Sync Level mechanism for this method, even though it is now serialized.
190*29492bb7SDavid van Moolenbroek * Otherwise, there can be conflicts with existing ASL code that actually
191*29492bb7SDavid van Moolenbroek * uses sync levels.
192*29492bb7SDavid van Moolenbroek */
193*29492bb7SDavid van Moolenbroek WalkState->MethodDesc->Method.SyncLevel = 0;
194*29492bb7SDavid van Moolenbroek WalkState->MethodDesc->Method.InfoFlags |=
195*29492bb7SDavid van Moolenbroek (ACPI_METHOD_SERIALIZED | ACPI_METHOD_IGNORE_SYNC_LEVEL);
196*29492bb7SDavid van Moolenbroek
197*29492bb7SDavid van Moolenbroek ACPI_DEBUG_PRINT ((ACPI_DB_INFO,
198*29492bb7SDavid van Moolenbroek "Method serialized [%4.4s] %p - [%s] (%4.4X)\n",
199*29492bb7SDavid van Moolenbroek WalkState->MethodNode->Name.Ascii, WalkState->MethodNode,
200*29492bb7SDavid van Moolenbroek WalkState->OpInfo->Name, WalkState->Opcode));
201*29492bb7SDavid van Moolenbroek
202*29492bb7SDavid van Moolenbroek /* Abort the parse, no need to examine this method any further */
203*29492bb7SDavid van Moolenbroek
204*29492bb7SDavid van Moolenbroek return (AE_CTRL_TERMINATE);
205*29492bb7SDavid van Moolenbroek }
206*29492bb7SDavid van Moolenbroek
207*29492bb7SDavid van Moolenbroek
208*29492bb7SDavid van Moolenbroek /*******************************************************************************
209*29492bb7SDavid van Moolenbroek *
210433d6423SLionel Sambuc * FUNCTION: AcpiDsMethodError
211433d6423SLionel Sambuc *
212433d6423SLionel Sambuc * PARAMETERS: Status - Execution status
213433d6423SLionel Sambuc * WalkState - Current state
214433d6423SLionel Sambuc *
215433d6423SLionel Sambuc * RETURN: Status
216433d6423SLionel Sambuc *
217433d6423SLionel Sambuc * DESCRIPTION: Called on method error. Invoke the global exception handler if
218433d6423SLionel Sambuc * present, dump the method data if the disassembler is configured
219433d6423SLionel Sambuc *
220433d6423SLionel Sambuc * Note: Allows the exception handler to change the status code
221433d6423SLionel Sambuc *
222433d6423SLionel Sambuc ******************************************************************************/
223433d6423SLionel Sambuc
224433d6423SLionel Sambuc ACPI_STATUS
AcpiDsMethodError(ACPI_STATUS Status,ACPI_WALK_STATE * WalkState)225433d6423SLionel Sambuc AcpiDsMethodError (
226433d6423SLionel Sambuc ACPI_STATUS Status,
227433d6423SLionel Sambuc ACPI_WALK_STATE *WalkState)
228433d6423SLionel Sambuc {
229433d6423SLionel Sambuc ACPI_FUNCTION_ENTRY ();
230433d6423SLionel Sambuc
231433d6423SLionel Sambuc
232433d6423SLionel Sambuc /* Ignore AE_OK and control exception codes */
233433d6423SLionel Sambuc
234433d6423SLionel Sambuc if (ACPI_SUCCESS (Status) ||
235433d6423SLionel Sambuc (Status & AE_CODE_CONTROL))
236433d6423SLionel Sambuc {
237433d6423SLionel Sambuc return (Status);
238433d6423SLionel Sambuc }
239433d6423SLionel Sambuc
240433d6423SLionel Sambuc /* Invoke the global exception handler */
241433d6423SLionel Sambuc
242433d6423SLionel Sambuc if (AcpiGbl_ExceptionHandler)
243433d6423SLionel Sambuc {
244433d6423SLionel Sambuc /* Exit the interpreter, allow handler to execute methods */
245433d6423SLionel Sambuc
246433d6423SLionel Sambuc AcpiExExitInterpreter ();
247433d6423SLionel Sambuc
248433d6423SLionel Sambuc /*
249433d6423SLionel Sambuc * Handler can map the exception code to anything it wants, including
250433d6423SLionel Sambuc * AE_OK, in which case the executing method will not be aborted.
251433d6423SLionel Sambuc */
252433d6423SLionel Sambuc Status = AcpiGbl_ExceptionHandler (Status,
253433d6423SLionel Sambuc WalkState->MethodNode ?
254433d6423SLionel Sambuc WalkState->MethodNode->Name.Integer : 0,
255433d6423SLionel Sambuc WalkState->Opcode, WalkState->AmlOffset, NULL);
256433d6423SLionel Sambuc AcpiExEnterInterpreter ();
257433d6423SLionel Sambuc }
258433d6423SLionel Sambuc
259433d6423SLionel Sambuc AcpiDsClearImplicitReturn (WalkState);
260433d6423SLionel Sambuc
261433d6423SLionel Sambuc #ifdef ACPI_DISASSEMBLER
262433d6423SLionel Sambuc if (ACPI_FAILURE (Status))
263433d6423SLionel Sambuc {
264433d6423SLionel Sambuc /* Display method locals/args if disassembler is present */
265433d6423SLionel Sambuc
266433d6423SLionel Sambuc AcpiDmDumpMethodInfo (Status, WalkState, WalkState->Op);
267433d6423SLionel Sambuc }
268433d6423SLionel Sambuc #endif
269433d6423SLionel Sambuc
270433d6423SLionel Sambuc return (Status);
271433d6423SLionel Sambuc }
272433d6423SLionel Sambuc
273433d6423SLionel Sambuc
274433d6423SLionel Sambuc /*******************************************************************************
275433d6423SLionel Sambuc *
276433d6423SLionel Sambuc * FUNCTION: AcpiDsCreateMethodMutex
277433d6423SLionel Sambuc *
278433d6423SLionel Sambuc * PARAMETERS: ObjDesc - The method object
279433d6423SLionel Sambuc *
280433d6423SLionel Sambuc * RETURN: Status
281433d6423SLionel Sambuc *
282433d6423SLionel Sambuc * DESCRIPTION: Create a mutex object for a serialized control method
283433d6423SLionel Sambuc *
284433d6423SLionel Sambuc ******************************************************************************/
285433d6423SLionel Sambuc
286433d6423SLionel Sambuc static ACPI_STATUS
AcpiDsCreateMethodMutex(ACPI_OPERAND_OBJECT * MethodDesc)287433d6423SLionel Sambuc AcpiDsCreateMethodMutex (
288433d6423SLionel Sambuc ACPI_OPERAND_OBJECT *MethodDesc)
289433d6423SLionel Sambuc {
290433d6423SLionel Sambuc ACPI_OPERAND_OBJECT *MutexDesc;
291433d6423SLionel Sambuc ACPI_STATUS Status;
292433d6423SLionel Sambuc
293433d6423SLionel Sambuc
294433d6423SLionel Sambuc ACPI_FUNCTION_TRACE (DsCreateMethodMutex);
295433d6423SLionel Sambuc
296433d6423SLionel Sambuc
297433d6423SLionel Sambuc /* Create the new mutex object */
298433d6423SLionel Sambuc
299433d6423SLionel Sambuc MutexDesc = AcpiUtCreateInternalObject (ACPI_TYPE_MUTEX);
300433d6423SLionel Sambuc if (!MutexDesc)
301433d6423SLionel Sambuc {
302433d6423SLionel Sambuc return_ACPI_STATUS (AE_NO_MEMORY);
303433d6423SLionel Sambuc }
304433d6423SLionel Sambuc
305433d6423SLionel Sambuc /* Create the actual OS Mutex */
306433d6423SLionel Sambuc
307433d6423SLionel Sambuc Status = AcpiOsCreateMutex (&MutexDesc->Mutex.OsMutex);
308433d6423SLionel Sambuc if (ACPI_FAILURE (Status))
309433d6423SLionel Sambuc {
310*29492bb7SDavid van Moolenbroek AcpiUtDeleteObjectDesc (MutexDesc);
311433d6423SLionel Sambuc return_ACPI_STATUS (Status);
312433d6423SLionel Sambuc }
313433d6423SLionel Sambuc
314433d6423SLionel Sambuc MutexDesc->Mutex.SyncLevel = MethodDesc->Method.SyncLevel;
315433d6423SLionel Sambuc MethodDesc->Method.Mutex = MutexDesc;
316433d6423SLionel Sambuc return_ACPI_STATUS (AE_OK);
317433d6423SLionel Sambuc }
318433d6423SLionel Sambuc
319433d6423SLionel Sambuc
320433d6423SLionel Sambuc /*******************************************************************************
321433d6423SLionel Sambuc *
322433d6423SLionel Sambuc * FUNCTION: AcpiDsBeginMethodExecution
323433d6423SLionel Sambuc *
324433d6423SLionel Sambuc * PARAMETERS: MethodNode - Node of the method
325433d6423SLionel Sambuc * ObjDesc - The method object
326433d6423SLionel Sambuc * WalkState - current state, NULL if not yet executing
327433d6423SLionel Sambuc * a method.
328433d6423SLionel Sambuc *
329433d6423SLionel Sambuc * RETURN: Status
330433d6423SLionel Sambuc *
331433d6423SLionel Sambuc * DESCRIPTION: Prepare a method for execution. Parses the method if necessary,
332433d6423SLionel Sambuc * increments the thread count, and waits at the method semaphore
333433d6423SLionel Sambuc * for clearance to execute.
334433d6423SLionel Sambuc *
335433d6423SLionel Sambuc ******************************************************************************/
336433d6423SLionel Sambuc
337433d6423SLionel Sambuc ACPI_STATUS
AcpiDsBeginMethodExecution(ACPI_NAMESPACE_NODE * MethodNode,ACPI_OPERAND_OBJECT * ObjDesc,ACPI_WALK_STATE * WalkState)338433d6423SLionel Sambuc AcpiDsBeginMethodExecution (
339433d6423SLionel Sambuc ACPI_NAMESPACE_NODE *MethodNode,
340433d6423SLionel Sambuc ACPI_OPERAND_OBJECT *ObjDesc,
341433d6423SLionel Sambuc ACPI_WALK_STATE *WalkState)
342433d6423SLionel Sambuc {
343433d6423SLionel Sambuc ACPI_STATUS Status = AE_OK;
344433d6423SLionel Sambuc
345433d6423SLionel Sambuc
346433d6423SLionel Sambuc ACPI_FUNCTION_TRACE_PTR (DsBeginMethodExecution, MethodNode);
347433d6423SLionel Sambuc
348433d6423SLionel Sambuc
349433d6423SLionel Sambuc if (!MethodNode)
350433d6423SLionel Sambuc {
351433d6423SLionel Sambuc return_ACPI_STATUS (AE_NULL_ENTRY);
352433d6423SLionel Sambuc }
353433d6423SLionel Sambuc
354433d6423SLionel Sambuc /* Prevent wraparound of thread count */
355433d6423SLionel Sambuc
356433d6423SLionel Sambuc if (ObjDesc->Method.ThreadCount == ACPI_UINT8_MAX)
357433d6423SLionel Sambuc {
358433d6423SLionel Sambuc ACPI_ERROR ((AE_INFO,
359433d6423SLionel Sambuc "Method reached maximum reentrancy limit (255)"));
360433d6423SLionel Sambuc return_ACPI_STATUS (AE_AML_METHOD_LIMIT);
361433d6423SLionel Sambuc }
362433d6423SLionel Sambuc
363433d6423SLionel Sambuc /*
364433d6423SLionel Sambuc * If this method is serialized, we need to acquire the method mutex.
365433d6423SLionel Sambuc */
366*29492bb7SDavid van Moolenbroek if (ObjDesc->Method.InfoFlags & ACPI_METHOD_SERIALIZED)
367433d6423SLionel Sambuc {
368433d6423SLionel Sambuc /*
369433d6423SLionel Sambuc * Create a mutex for the method if it is defined to be Serialized
370433d6423SLionel Sambuc * and a mutex has not already been created. We defer the mutex creation
371433d6423SLionel Sambuc * until a method is actually executed, to minimize the object count
372433d6423SLionel Sambuc */
373433d6423SLionel Sambuc if (!ObjDesc->Method.Mutex)
374433d6423SLionel Sambuc {
375433d6423SLionel Sambuc Status = AcpiDsCreateMethodMutex (ObjDesc);
376433d6423SLionel Sambuc if (ACPI_FAILURE (Status))
377433d6423SLionel Sambuc {
378433d6423SLionel Sambuc return_ACPI_STATUS (Status);
379433d6423SLionel Sambuc }
380433d6423SLionel Sambuc }
381433d6423SLionel Sambuc
382433d6423SLionel Sambuc /*
383433d6423SLionel Sambuc * The CurrentSyncLevel (per-thread) must be less than or equal to
384433d6423SLionel Sambuc * the sync level of the method. This mechanism provides some
385*29492bb7SDavid van Moolenbroek * deadlock prevention.
386*29492bb7SDavid van Moolenbroek *
387*29492bb7SDavid van Moolenbroek * If the method was auto-serialized, we just ignore the sync level
388*29492bb7SDavid van Moolenbroek * mechanism, because auto-serialization of methods can interfere
389*29492bb7SDavid van Moolenbroek * with ASL code that actually uses sync levels.
390433d6423SLionel Sambuc *
391433d6423SLionel Sambuc * Top-level method invocation has no walk state at this point
392433d6423SLionel Sambuc */
393433d6423SLionel Sambuc if (WalkState &&
394*29492bb7SDavid van Moolenbroek (!(ObjDesc->Method.InfoFlags & ACPI_METHOD_IGNORE_SYNC_LEVEL)) &&
395433d6423SLionel Sambuc (WalkState->Thread->CurrentSyncLevel > ObjDesc->Method.Mutex->Mutex.SyncLevel))
396433d6423SLionel Sambuc {
397433d6423SLionel Sambuc ACPI_ERROR ((AE_INFO,
398433d6423SLionel Sambuc "Cannot acquire Mutex for method [%4.4s], current SyncLevel is too large (%u)",
399433d6423SLionel Sambuc AcpiUtGetNodeName (MethodNode),
400433d6423SLionel Sambuc WalkState->Thread->CurrentSyncLevel));
401433d6423SLionel Sambuc
402433d6423SLionel Sambuc return_ACPI_STATUS (AE_AML_MUTEX_ORDER);
403433d6423SLionel Sambuc }
404433d6423SLionel Sambuc
405433d6423SLionel Sambuc /*
406433d6423SLionel Sambuc * Obtain the method mutex if necessary. Do not acquire mutex for a
407433d6423SLionel Sambuc * recursive call.
408433d6423SLionel Sambuc */
409433d6423SLionel Sambuc if (!WalkState ||
410433d6423SLionel Sambuc !ObjDesc->Method.Mutex->Mutex.ThreadId ||
411433d6423SLionel Sambuc (WalkState->Thread->ThreadId != ObjDesc->Method.Mutex->Mutex.ThreadId))
412433d6423SLionel Sambuc {
413433d6423SLionel Sambuc /*
414433d6423SLionel Sambuc * Acquire the method mutex. This releases the interpreter if we
415433d6423SLionel Sambuc * block (and reacquires it before it returns)
416433d6423SLionel Sambuc */
417433d6423SLionel Sambuc Status = AcpiExSystemWaitMutex (ObjDesc->Method.Mutex->Mutex.OsMutex,
418433d6423SLionel Sambuc ACPI_WAIT_FOREVER);
419433d6423SLionel Sambuc if (ACPI_FAILURE (Status))
420433d6423SLionel Sambuc {
421433d6423SLionel Sambuc return_ACPI_STATUS (Status);
422433d6423SLionel Sambuc }
423433d6423SLionel Sambuc
424433d6423SLionel Sambuc /* Update the mutex and walk info and save the original SyncLevel */
425433d6423SLionel Sambuc
426433d6423SLionel Sambuc if (WalkState)
427433d6423SLionel Sambuc {
428433d6423SLionel Sambuc ObjDesc->Method.Mutex->Mutex.OriginalSyncLevel =
429433d6423SLionel Sambuc WalkState->Thread->CurrentSyncLevel;
430433d6423SLionel Sambuc
431433d6423SLionel Sambuc ObjDesc->Method.Mutex->Mutex.ThreadId = WalkState->Thread->ThreadId;
432433d6423SLionel Sambuc WalkState->Thread->CurrentSyncLevel = ObjDesc->Method.SyncLevel;
433433d6423SLionel Sambuc }
434433d6423SLionel Sambuc else
435433d6423SLionel Sambuc {
436433d6423SLionel Sambuc ObjDesc->Method.Mutex->Mutex.OriginalSyncLevel =
437433d6423SLionel Sambuc ObjDesc->Method.Mutex->Mutex.SyncLevel;
438433d6423SLionel Sambuc }
439433d6423SLionel Sambuc }
440433d6423SLionel Sambuc
441433d6423SLionel Sambuc /* Always increase acquisition depth */
442433d6423SLionel Sambuc
443433d6423SLionel Sambuc ObjDesc->Method.Mutex->Mutex.AcquisitionDepth++;
444433d6423SLionel Sambuc }
445433d6423SLionel Sambuc
446433d6423SLionel Sambuc /*
447433d6423SLionel Sambuc * Allocate an Owner ID for this method, only if this is the first thread
448433d6423SLionel Sambuc * to begin concurrent execution. We only need one OwnerId, even if the
449433d6423SLionel Sambuc * method is invoked recursively.
450433d6423SLionel Sambuc */
451433d6423SLionel Sambuc if (!ObjDesc->Method.OwnerId)
452433d6423SLionel Sambuc {
453433d6423SLionel Sambuc Status = AcpiUtAllocateOwnerId (&ObjDesc->Method.OwnerId);
454433d6423SLionel Sambuc if (ACPI_FAILURE (Status))
455433d6423SLionel Sambuc {
456433d6423SLionel Sambuc goto Cleanup;
457433d6423SLionel Sambuc }
458433d6423SLionel Sambuc }
459433d6423SLionel Sambuc
460433d6423SLionel Sambuc /*
461433d6423SLionel Sambuc * Increment the method parse tree thread count since it has been
462433d6423SLionel Sambuc * reentered one more time (even if it is the same thread)
463433d6423SLionel Sambuc */
464433d6423SLionel Sambuc ObjDesc->Method.ThreadCount++;
465433d6423SLionel Sambuc AcpiMethodCount++;
466433d6423SLionel Sambuc return_ACPI_STATUS (Status);
467433d6423SLionel Sambuc
468433d6423SLionel Sambuc
469433d6423SLionel Sambuc Cleanup:
470433d6423SLionel Sambuc /* On error, must release the method mutex (if present) */
471433d6423SLionel Sambuc
472433d6423SLionel Sambuc if (ObjDesc->Method.Mutex)
473433d6423SLionel Sambuc {
474433d6423SLionel Sambuc AcpiOsReleaseMutex (ObjDesc->Method.Mutex->Mutex.OsMutex);
475433d6423SLionel Sambuc }
476433d6423SLionel Sambuc return_ACPI_STATUS (Status);
477433d6423SLionel Sambuc }
478433d6423SLionel Sambuc
479433d6423SLionel Sambuc
480433d6423SLionel Sambuc /*******************************************************************************
481433d6423SLionel Sambuc *
482433d6423SLionel Sambuc * FUNCTION: AcpiDsCallControlMethod
483433d6423SLionel Sambuc *
484433d6423SLionel Sambuc * PARAMETERS: Thread - Info for this thread
485433d6423SLionel Sambuc * ThisWalkState - Current walk state
486433d6423SLionel Sambuc * Op - Current Op to be walked
487433d6423SLionel Sambuc *
488433d6423SLionel Sambuc * RETURN: Status
489433d6423SLionel Sambuc *
490433d6423SLionel Sambuc * DESCRIPTION: Transfer execution to a called control method
491433d6423SLionel Sambuc *
492433d6423SLionel Sambuc ******************************************************************************/
493433d6423SLionel Sambuc
494433d6423SLionel Sambuc ACPI_STATUS
AcpiDsCallControlMethod(ACPI_THREAD_STATE * Thread,ACPI_WALK_STATE * ThisWalkState,ACPI_PARSE_OBJECT * Op)495433d6423SLionel Sambuc AcpiDsCallControlMethod (
496433d6423SLionel Sambuc ACPI_THREAD_STATE *Thread,
497433d6423SLionel Sambuc ACPI_WALK_STATE *ThisWalkState,
498433d6423SLionel Sambuc ACPI_PARSE_OBJECT *Op)
499433d6423SLionel Sambuc {
500433d6423SLionel Sambuc ACPI_STATUS Status;
501433d6423SLionel Sambuc ACPI_NAMESPACE_NODE *MethodNode;
502433d6423SLionel Sambuc ACPI_WALK_STATE *NextWalkState = NULL;
503433d6423SLionel Sambuc ACPI_OPERAND_OBJECT *ObjDesc;
504433d6423SLionel Sambuc ACPI_EVALUATE_INFO *Info;
505433d6423SLionel Sambuc UINT32 i;
506433d6423SLionel Sambuc
507433d6423SLionel Sambuc
508433d6423SLionel Sambuc ACPI_FUNCTION_TRACE_PTR (DsCallControlMethod, ThisWalkState);
509433d6423SLionel Sambuc
510433d6423SLionel Sambuc ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "Calling method %p, currentstate=%p\n",
511433d6423SLionel Sambuc ThisWalkState->PrevOp, ThisWalkState));
512433d6423SLionel Sambuc
513433d6423SLionel Sambuc /*
514433d6423SLionel Sambuc * Get the namespace entry for the control method we are about to call
515433d6423SLionel Sambuc */
516433d6423SLionel Sambuc MethodNode = ThisWalkState->MethodCallNode;
517433d6423SLionel Sambuc if (!MethodNode)
518433d6423SLionel Sambuc {
519433d6423SLionel Sambuc return_ACPI_STATUS (AE_NULL_ENTRY);
520433d6423SLionel Sambuc }
521433d6423SLionel Sambuc
522433d6423SLionel Sambuc ObjDesc = AcpiNsGetAttachedObject (MethodNode);
523433d6423SLionel Sambuc if (!ObjDesc)
524433d6423SLionel Sambuc {
525433d6423SLionel Sambuc return_ACPI_STATUS (AE_NULL_OBJECT);
526433d6423SLionel Sambuc }
527433d6423SLionel Sambuc
528433d6423SLionel Sambuc /* Init for new method, possibly wait on method mutex */
529433d6423SLionel Sambuc
530433d6423SLionel Sambuc Status = AcpiDsBeginMethodExecution (MethodNode, ObjDesc,
531433d6423SLionel Sambuc ThisWalkState);
532433d6423SLionel Sambuc if (ACPI_FAILURE (Status))
533433d6423SLionel Sambuc {
534433d6423SLionel Sambuc return_ACPI_STATUS (Status);
535433d6423SLionel Sambuc }
536433d6423SLionel Sambuc
537433d6423SLionel Sambuc /* Begin method parse/execution. Create a new walk state */
538433d6423SLionel Sambuc
539433d6423SLionel Sambuc NextWalkState = AcpiDsCreateWalkState (ObjDesc->Method.OwnerId,
540433d6423SLionel Sambuc NULL, ObjDesc, Thread);
541433d6423SLionel Sambuc if (!NextWalkState)
542433d6423SLionel Sambuc {
543433d6423SLionel Sambuc Status = AE_NO_MEMORY;
544433d6423SLionel Sambuc goto Cleanup;
545433d6423SLionel Sambuc }
546433d6423SLionel Sambuc
547433d6423SLionel Sambuc /*
548433d6423SLionel Sambuc * The resolved arguments were put on the previous walk state's operand
549433d6423SLionel Sambuc * stack. Operands on the previous walk state stack always
550433d6423SLionel Sambuc * start at index 0. Also, null terminate the list of arguments
551433d6423SLionel Sambuc */
552433d6423SLionel Sambuc ThisWalkState->Operands [ThisWalkState->NumOperands] = NULL;
553433d6423SLionel Sambuc
554433d6423SLionel Sambuc /*
555433d6423SLionel Sambuc * Allocate and initialize the evaluation information block
556433d6423SLionel Sambuc * TBD: this is somewhat inefficient, should change interface to
557433d6423SLionel Sambuc * DsInitAmlWalk. For now, keeps this struct off the CPU stack
558433d6423SLionel Sambuc */
559433d6423SLionel Sambuc Info = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_EVALUATE_INFO));
560433d6423SLionel Sambuc if (!Info)
561433d6423SLionel Sambuc {
562*29492bb7SDavid van Moolenbroek Status = AE_NO_MEMORY;
563*29492bb7SDavid van Moolenbroek goto Cleanup;
564433d6423SLionel Sambuc }
565433d6423SLionel Sambuc
566433d6423SLionel Sambuc Info->Parameters = &ThisWalkState->Operands[0];
567433d6423SLionel Sambuc
568433d6423SLionel Sambuc Status = AcpiDsInitAmlWalk (NextWalkState, NULL, MethodNode,
569433d6423SLionel Sambuc ObjDesc->Method.AmlStart, ObjDesc->Method.AmlLength,
570433d6423SLionel Sambuc Info, ACPI_IMODE_EXECUTE);
571433d6423SLionel Sambuc
572433d6423SLionel Sambuc ACPI_FREE (Info);
573433d6423SLionel Sambuc if (ACPI_FAILURE (Status))
574433d6423SLionel Sambuc {
575433d6423SLionel Sambuc goto Cleanup;
576433d6423SLionel Sambuc }
577433d6423SLionel Sambuc
578433d6423SLionel Sambuc /*
579433d6423SLionel Sambuc * Delete the operands on the previous walkstate operand stack
580433d6423SLionel Sambuc * (they were copied to new objects)
581433d6423SLionel Sambuc */
582433d6423SLionel Sambuc for (i = 0; i < ObjDesc->Method.ParamCount; i++)
583433d6423SLionel Sambuc {
584433d6423SLionel Sambuc AcpiUtRemoveReference (ThisWalkState->Operands [i]);
585433d6423SLionel Sambuc ThisWalkState->Operands [i] = NULL;
586433d6423SLionel Sambuc }
587433d6423SLionel Sambuc
588433d6423SLionel Sambuc /* Clear the operand stack */
589433d6423SLionel Sambuc
590433d6423SLionel Sambuc ThisWalkState->NumOperands = 0;
591433d6423SLionel Sambuc
592433d6423SLionel Sambuc ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
593433d6423SLionel Sambuc "**** Begin nested execution of [%4.4s] **** WalkState=%p\n",
594433d6423SLionel Sambuc MethodNode->Name.Ascii, NextWalkState));
595433d6423SLionel Sambuc
596433d6423SLionel Sambuc /* Invoke an internal method if necessary */
597433d6423SLionel Sambuc
598*29492bb7SDavid van Moolenbroek if (ObjDesc->Method.InfoFlags & ACPI_METHOD_INTERNAL_ONLY)
599433d6423SLionel Sambuc {
600*29492bb7SDavid van Moolenbroek Status = ObjDesc->Method.Dispatch.Implementation (NextWalkState);
601433d6423SLionel Sambuc if (Status == AE_OK)
602433d6423SLionel Sambuc {
603433d6423SLionel Sambuc Status = AE_CTRL_TERMINATE;
604433d6423SLionel Sambuc }
605433d6423SLionel Sambuc }
606433d6423SLionel Sambuc
607433d6423SLionel Sambuc return_ACPI_STATUS (Status);
608433d6423SLionel Sambuc
609433d6423SLionel Sambuc
610433d6423SLionel Sambuc Cleanup:
611433d6423SLionel Sambuc
612433d6423SLionel Sambuc /* On error, we must terminate the method properly */
613433d6423SLionel Sambuc
614433d6423SLionel Sambuc AcpiDsTerminateControlMethod (ObjDesc, NextWalkState);
615433d6423SLionel Sambuc if (NextWalkState)
616433d6423SLionel Sambuc {
617433d6423SLionel Sambuc AcpiDsDeleteWalkState (NextWalkState);
618433d6423SLionel Sambuc }
619433d6423SLionel Sambuc
620433d6423SLionel Sambuc return_ACPI_STATUS (Status);
621433d6423SLionel Sambuc }
622433d6423SLionel Sambuc
623433d6423SLionel Sambuc
624433d6423SLionel Sambuc /*******************************************************************************
625433d6423SLionel Sambuc *
626433d6423SLionel Sambuc * FUNCTION: AcpiDsRestartControlMethod
627433d6423SLionel Sambuc *
628433d6423SLionel Sambuc * PARAMETERS: WalkState - State for preempted method (caller)
629433d6423SLionel Sambuc * ReturnDesc - Return value from the called method
630433d6423SLionel Sambuc *
631433d6423SLionel Sambuc * RETURN: Status
632433d6423SLionel Sambuc *
633433d6423SLionel Sambuc * DESCRIPTION: Restart a method that was preempted by another (nested) method
634433d6423SLionel Sambuc * invocation. Handle the return value (if any) from the callee.
635433d6423SLionel Sambuc *
636433d6423SLionel Sambuc ******************************************************************************/
637433d6423SLionel Sambuc
638433d6423SLionel Sambuc ACPI_STATUS
AcpiDsRestartControlMethod(ACPI_WALK_STATE * WalkState,ACPI_OPERAND_OBJECT * ReturnDesc)639433d6423SLionel Sambuc AcpiDsRestartControlMethod (
640433d6423SLionel Sambuc ACPI_WALK_STATE *WalkState,
641433d6423SLionel Sambuc ACPI_OPERAND_OBJECT *ReturnDesc)
642433d6423SLionel Sambuc {
643433d6423SLionel Sambuc ACPI_STATUS Status;
644433d6423SLionel Sambuc int SameAsImplicitReturn;
645433d6423SLionel Sambuc
646433d6423SLionel Sambuc
647433d6423SLionel Sambuc ACPI_FUNCTION_TRACE_PTR (DsRestartControlMethod, WalkState);
648433d6423SLionel Sambuc
649433d6423SLionel Sambuc
650433d6423SLionel Sambuc ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
651433d6423SLionel Sambuc "****Restart [%4.4s] Op %p ReturnValueFromCallee %p\n",
652433d6423SLionel Sambuc AcpiUtGetNodeName (WalkState->MethodNode),
653433d6423SLionel Sambuc WalkState->MethodCallOp, ReturnDesc));
654433d6423SLionel Sambuc
655433d6423SLionel Sambuc ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
656433d6423SLionel Sambuc " ReturnFromThisMethodUsed?=%X ResStack %p Walk %p\n",
657433d6423SLionel Sambuc WalkState->ReturnUsed,
658433d6423SLionel Sambuc WalkState->Results, WalkState));
659433d6423SLionel Sambuc
660433d6423SLionel Sambuc /* Did the called method return a value? */
661433d6423SLionel Sambuc
662433d6423SLionel Sambuc if (ReturnDesc)
663433d6423SLionel Sambuc {
664433d6423SLionel Sambuc /* Is the implicit return object the same as the return desc? */
665433d6423SLionel Sambuc
666433d6423SLionel Sambuc SameAsImplicitReturn = (WalkState->ImplicitReturnObj == ReturnDesc);
667433d6423SLionel Sambuc
668433d6423SLionel Sambuc /* Are we actually going to use the return value? */
669433d6423SLionel Sambuc
670433d6423SLionel Sambuc if (WalkState->ReturnUsed)
671433d6423SLionel Sambuc {
672433d6423SLionel Sambuc /* Save the return value from the previous method */
673433d6423SLionel Sambuc
674433d6423SLionel Sambuc Status = AcpiDsResultPush (ReturnDesc, WalkState);
675433d6423SLionel Sambuc if (ACPI_FAILURE (Status))
676433d6423SLionel Sambuc {
677433d6423SLionel Sambuc AcpiUtRemoveReference (ReturnDesc);
678433d6423SLionel Sambuc return_ACPI_STATUS (Status);
679433d6423SLionel Sambuc }
680433d6423SLionel Sambuc
681433d6423SLionel Sambuc /*
682433d6423SLionel Sambuc * Save as THIS method's return value in case it is returned
683433d6423SLionel Sambuc * immediately to yet another method
684433d6423SLionel Sambuc */
685433d6423SLionel Sambuc WalkState->ReturnDesc = ReturnDesc;
686433d6423SLionel Sambuc }
687433d6423SLionel Sambuc
688433d6423SLionel Sambuc /*
689433d6423SLionel Sambuc * The following code is the optional support for the so-called
690433d6423SLionel Sambuc * "implicit return". Some AML code assumes that the last value of the
691433d6423SLionel Sambuc * method is "implicitly" returned to the caller, in the absence of an
692433d6423SLionel Sambuc * explicit return value.
693433d6423SLionel Sambuc *
694433d6423SLionel Sambuc * Just save the last result of the method as the return value.
695433d6423SLionel Sambuc *
696433d6423SLionel Sambuc * NOTE: this is optional because the ASL language does not actually
697433d6423SLionel Sambuc * support this behavior.
698433d6423SLionel Sambuc */
699433d6423SLionel Sambuc else if (!AcpiDsDoImplicitReturn (ReturnDesc, WalkState, FALSE) ||
700433d6423SLionel Sambuc SameAsImplicitReturn)
701433d6423SLionel Sambuc {
702433d6423SLionel Sambuc /*
703433d6423SLionel Sambuc * Delete the return value if it will not be used by the
704433d6423SLionel Sambuc * calling method or remove one reference if the explicit return
705433d6423SLionel Sambuc * is the same as the implicit return value.
706433d6423SLionel Sambuc */
707433d6423SLionel Sambuc AcpiUtRemoveReference (ReturnDesc);
708433d6423SLionel Sambuc }
709433d6423SLionel Sambuc }
710433d6423SLionel Sambuc
711433d6423SLionel Sambuc return_ACPI_STATUS (AE_OK);
712433d6423SLionel Sambuc }
713433d6423SLionel Sambuc
714433d6423SLionel Sambuc
715433d6423SLionel Sambuc /*******************************************************************************
716433d6423SLionel Sambuc *
717433d6423SLionel Sambuc * FUNCTION: AcpiDsTerminateControlMethod
718433d6423SLionel Sambuc *
719433d6423SLionel Sambuc * PARAMETERS: MethodDesc - Method object
720433d6423SLionel Sambuc * WalkState - State associated with the method
721433d6423SLionel Sambuc *
722433d6423SLionel Sambuc * RETURN: None
723433d6423SLionel Sambuc *
724433d6423SLionel Sambuc * DESCRIPTION: Terminate a control method. Delete everything that the method
725433d6423SLionel Sambuc * created, delete all locals and arguments, and delete the parse
726433d6423SLionel Sambuc * tree if requested.
727433d6423SLionel Sambuc *
728433d6423SLionel Sambuc * MUTEX: Interpreter is locked
729433d6423SLionel Sambuc *
730433d6423SLionel Sambuc ******************************************************************************/
731433d6423SLionel Sambuc
732433d6423SLionel Sambuc void
AcpiDsTerminateControlMethod(ACPI_OPERAND_OBJECT * MethodDesc,ACPI_WALK_STATE * WalkState)733433d6423SLionel Sambuc AcpiDsTerminateControlMethod (
734433d6423SLionel Sambuc ACPI_OPERAND_OBJECT *MethodDesc,
735433d6423SLionel Sambuc ACPI_WALK_STATE *WalkState)
736433d6423SLionel Sambuc {
737433d6423SLionel Sambuc
738433d6423SLionel Sambuc ACPI_FUNCTION_TRACE_PTR (DsTerminateControlMethod, WalkState);
739433d6423SLionel Sambuc
740433d6423SLionel Sambuc
741433d6423SLionel Sambuc /* MethodDesc is required, WalkState is optional */
742433d6423SLionel Sambuc
743433d6423SLionel Sambuc if (!MethodDesc)
744433d6423SLionel Sambuc {
745433d6423SLionel Sambuc return_VOID;
746433d6423SLionel Sambuc }
747433d6423SLionel Sambuc
748433d6423SLionel Sambuc if (WalkState)
749433d6423SLionel Sambuc {
750433d6423SLionel Sambuc /* Delete all arguments and locals */
751433d6423SLionel Sambuc
752433d6423SLionel Sambuc AcpiDsMethodDataDeleteAll (WalkState);
753433d6423SLionel Sambuc
754433d6423SLionel Sambuc /*
755433d6423SLionel Sambuc * If method is serialized, release the mutex and restore the
756433d6423SLionel Sambuc * current sync level for this thread
757433d6423SLionel Sambuc */
758433d6423SLionel Sambuc if (MethodDesc->Method.Mutex)
759433d6423SLionel Sambuc {
760433d6423SLionel Sambuc /* Acquisition Depth handles recursive calls */
761433d6423SLionel Sambuc
762433d6423SLionel Sambuc MethodDesc->Method.Mutex->Mutex.AcquisitionDepth--;
763433d6423SLionel Sambuc if (!MethodDesc->Method.Mutex->Mutex.AcquisitionDepth)
764433d6423SLionel Sambuc {
765433d6423SLionel Sambuc WalkState->Thread->CurrentSyncLevel =
766433d6423SLionel Sambuc MethodDesc->Method.Mutex->Mutex.OriginalSyncLevel;
767433d6423SLionel Sambuc
768433d6423SLionel Sambuc AcpiOsReleaseMutex (MethodDesc->Method.Mutex->Mutex.OsMutex);
769433d6423SLionel Sambuc MethodDesc->Method.Mutex->Mutex.ThreadId = 0;
770433d6423SLionel Sambuc }
771433d6423SLionel Sambuc }
772433d6423SLionel Sambuc
773433d6423SLionel Sambuc /*
774433d6423SLionel Sambuc * Delete any namespace objects created anywhere within the
775*29492bb7SDavid van Moolenbroek * namespace by the execution of this method. Unless:
776*29492bb7SDavid van Moolenbroek * 1) This method is a module-level executable code method, in which
777*29492bb7SDavid van Moolenbroek * case we want make the objects permanent.
778*29492bb7SDavid van Moolenbroek * 2) There are other threads executing the method, in which case we
779*29492bb7SDavid van Moolenbroek * will wait until the last thread has completed.
780433d6423SLionel Sambuc */
781*29492bb7SDavid van Moolenbroek if (!(MethodDesc->Method.InfoFlags & ACPI_METHOD_MODULE_LEVEL) &&
782*29492bb7SDavid van Moolenbroek (MethodDesc->Method.ThreadCount == 1))
783433d6423SLionel Sambuc {
784433d6423SLionel Sambuc /* Delete any direct children of (created by) this method */
785433d6423SLionel Sambuc
786433d6423SLionel Sambuc AcpiNsDeleteNamespaceSubtree (WalkState->MethodNode);
787433d6423SLionel Sambuc
788433d6423SLionel Sambuc /*
789433d6423SLionel Sambuc * Delete any objects that were created by this method
790433d6423SLionel Sambuc * elsewhere in the namespace (if any were created).
791*29492bb7SDavid van Moolenbroek * Use of the ACPI_METHOD_MODIFIED_NAMESPACE optimizes the
792*29492bb7SDavid van Moolenbroek * deletion such that we don't have to perform an entire
793*29492bb7SDavid van Moolenbroek * namespace walk for every control method execution.
794433d6423SLionel Sambuc */
795*29492bb7SDavid van Moolenbroek if (MethodDesc->Method.InfoFlags & ACPI_METHOD_MODIFIED_NAMESPACE)
796433d6423SLionel Sambuc {
797433d6423SLionel Sambuc AcpiNsDeleteNamespaceByOwner (MethodDesc->Method.OwnerId);
798*29492bb7SDavid van Moolenbroek MethodDesc->Method.InfoFlags &= ~ACPI_METHOD_MODIFIED_NAMESPACE;
799433d6423SLionel Sambuc }
800433d6423SLionel Sambuc }
801433d6423SLionel Sambuc }
802433d6423SLionel Sambuc
803433d6423SLionel Sambuc /* Decrement the thread count on the method */
804433d6423SLionel Sambuc
805433d6423SLionel Sambuc if (MethodDesc->Method.ThreadCount)
806433d6423SLionel Sambuc {
807433d6423SLionel Sambuc MethodDesc->Method.ThreadCount--;
808433d6423SLionel Sambuc }
809433d6423SLionel Sambuc else
810433d6423SLionel Sambuc {
811433d6423SLionel Sambuc ACPI_ERROR ((AE_INFO,
812433d6423SLionel Sambuc "Invalid zero thread count in method"));
813433d6423SLionel Sambuc }
814433d6423SLionel Sambuc
815433d6423SLionel Sambuc /* Are there any other threads currently executing this method? */
816433d6423SLionel Sambuc
817433d6423SLionel Sambuc if (MethodDesc->Method.ThreadCount)
818433d6423SLionel Sambuc {
819433d6423SLionel Sambuc /*
820433d6423SLionel Sambuc * Additional threads. Do not release the OwnerId in this case,
821433d6423SLionel Sambuc * we immediately reuse it for the next thread executing this method
822433d6423SLionel Sambuc */
823433d6423SLionel Sambuc ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
824433d6423SLionel Sambuc "*** Completed execution of one thread, %u threads remaining\n",
825433d6423SLionel Sambuc MethodDesc->Method.ThreadCount));
826433d6423SLionel Sambuc }
827433d6423SLionel Sambuc else
828433d6423SLionel Sambuc {
829433d6423SLionel Sambuc /* This is the only executing thread for this method */
830433d6423SLionel Sambuc
831433d6423SLionel Sambuc /*
832433d6423SLionel Sambuc * Support to dynamically change a method from NotSerialized to
833433d6423SLionel Sambuc * Serialized if it appears that the method is incorrectly written and
834433d6423SLionel Sambuc * does not support multiple thread execution. The best example of this
835433d6423SLionel Sambuc * is if such a method creates namespace objects and blocks. A second
836*29492bb7SDavid van Moolenbroek * thread will fail with an AE_ALREADY_EXISTS exception.
837433d6423SLionel Sambuc *
838433d6423SLionel Sambuc * This code is here because we must wait until the last thread exits
839*29492bb7SDavid van Moolenbroek * before marking the method as serialized.
840433d6423SLionel Sambuc */
841*29492bb7SDavid van Moolenbroek if (MethodDesc->Method.InfoFlags & ACPI_METHOD_SERIALIZED_PENDING)
842433d6423SLionel Sambuc {
843*29492bb7SDavid van Moolenbroek if (WalkState)
844*29492bb7SDavid van Moolenbroek {
845*29492bb7SDavid van Moolenbroek ACPI_INFO ((AE_INFO,
846*29492bb7SDavid van Moolenbroek "Marking method %4.4s as Serialized because of AE_ALREADY_EXISTS error",
847*29492bb7SDavid van Moolenbroek WalkState->MethodNode->Name.Ascii));
848*29492bb7SDavid van Moolenbroek }
849*29492bb7SDavid van Moolenbroek
850*29492bb7SDavid van Moolenbroek /*
851*29492bb7SDavid van Moolenbroek * Method tried to create an object twice and was marked as
852*29492bb7SDavid van Moolenbroek * "pending serialized". The probable cause is that the method
853*29492bb7SDavid van Moolenbroek * cannot handle reentrancy.
854*29492bb7SDavid van Moolenbroek *
855*29492bb7SDavid van Moolenbroek * The method was created as NotSerialized, but it tried to create
856*29492bb7SDavid van Moolenbroek * a named object and then blocked, causing the second thread
857*29492bb7SDavid van Moolenbroek * entrance to begin and then fail. Workaround this problem by
858*29492bb7SDavid van Moolenbroek * marking the method permanently as Serialized when the last
859*29492bb7SDavid van Moolenbroek * thread exits here.
860*29492bb7SDavid van Moolenbroek */
861*29492bb7SDavid van Moolenbroek MethodDesc->Method.InfoFlags &= ~ACPI_METHOD_SERIALIZED_PENDING;
862*29492bb7SDavid van Moolenbroek MethodDesc->Method.InfoFlags |=
863*29492bb7SDavid van Moolenbroek (ACPI_METHOD_SERIALIZED | ACPI_METHOD_IGNORE_SYNC_LEVEL);
864*29492bb7SDavid van Moolenbroek MethodDesc->Method.SyncLevel = 0;
865433d6423SLionel Sambuc }
866433d6423SLionel Sambuc
867433d6423SLionel Sambuc /* No more threads, we can free the OwnerId */
868433d6423SLionel Sambuc
869*29492bb7SDavid van Moolenbroek if (!(MethodDesc->Method.InfoFlags & ACPI_METHOD_MODULE_LEVEL))
870433d6423SLionel Sambuc {
871433d6423SLionel Sambuc AcpiUtReleaseOwnerId (&MethodDesc->Method.OwnerId);
872433d6423SLionel Sambuc }
873433d6423SLionel Sambuc }
874433d6423SLionel Sambuc
875433d6423SLionel Sambuc return_VOID;
876433d6423SLionel Sambuc }
877