10d02842fSSascha Wildner /******************************************************************************
20d02842fSSascha Wildner *
30d02842fSSascha Wildner * Module Name: dsmethod - Parser/Interpreter interface - control method parsing
40d02842fSSascha Wildner *
50d02842fSSascha Wildner *****************************************************************************/
60d02842fSSascha Wildner
7b4315fc7SSascha Wildner /******************************************************************************
8b4315fc7SSascha Wildner *
9b4315fc7SSascha Wildner * 1. Copyright Notice
10b4315fc7SSascha Wildner *
11*383048acSSascha Wildner * Some or all of this work - Copyright (c) 1999 - 2021, Intel Corp.
120d02842fSSascha Wildner * All rights reserved.
130d02842fSSascha Wildner *
14b4315fc7SSascha Wildner * 2. License
15b4315fc7SSascha Wildner *
16b4315fc7SSascha Wildner * 2.1. This is your license from Intel Corp. under its intellectual property
17b4315fc7SSascha Wildner * rights. You may have additional license terms from the party that provided
18b4315fc7SSascha Wildner * you this software, covering your right to use that party's intellectual
19b4315fc7SSascha Wildner * property rights.
20b4315fc7SSascha Wildner *
21b4315fc7SSascha Wildner * 2.2. Intel grants, free of charge, to any person ("Licensee") obtaining a
22b4315fc7SSascha Wildner * copy of the source code appearing in this file ("Covered Code") an
23b4315fc7SSascha Wildner * irrevocable, perpetual, worldwide license under Intel's copyrights in the
24b4315fc7SSascha Wildner * base code distributed originally by Intel ("Original Intel Code") to copy,
25b4315fc7SSascha Wildner * make derivatives, distribute, use and display any portion of the Covered
26b4315fc7SSascha Wildner * Code in any form, with the right to sublicense such rights; and
27b4315fc7SSascha Wildner *
28b4315fc7SSascha Wildner * 2.3. Intel grants Licensee a non-exclusive and non-transferable patent
29b4315fc7SSascha Wildner * license (with the right to sublicense), under only those claims of Intel
30b4315fc7SSascha Wildner * patents that are infringed by the Original Intel Code, to make, use, sell,
31b4315fc7SSascha Wildner * offer to sell, and import the Covered Code and derivative works thereof
32b4315fc7SSascha Wildner * solely to the minimum extent necessary to exercise the above copyright
33b4315fc7SSascha Wildner * license, and in no event shall the patent license extend to any additions
34b4315fc7SSascha Wildner * to or modifications of the Original Intel Code. No other license or right
35b4315fc7SSascha Wildner * is granted directly or by implication, estoppel or otherwise;
36b4315fc7SSascha Wildner *
37b4315fc7SSascha Wildner * The above copyright and patent license is granted only if the following
38b4315fc7SSascha Wildner * conditions are met:
39b4315fc7SSascha Wildner *
40b4315fc7SSascha Wildner * 3. Conditions
41b4315fc7SSascha Wildner *
42b4315fc7SSascha Wildner * 3.1. Redistribution of Source with Rights to Further Distribute Source.
43b4315fc7SSascha Wildner * Redistribution of source code of any substantial portion of the Covered
44b4315fc7SSascha Wildner * Code or modification with rights to further distribute source must include
45b4315fc7SSascha Wildner * the above Copyright Notice, the above License, this list of Conditions,
46b4315fc7SSascha Wildner * and the following Disclaimer and Export Compliance provision. In addition,
47b4315fc7SSascha Wildner * Licensee must cause all Covered Code to which Licensee contributes to
48b4315fc7SSascha Wildner * contain a file documenting the changes Licensee made to create that Covered
49b4315fc7SSascha Wildner * Code and the date of any change. Licensee must include in that file the
50b4315fc7SSascha Wildner * documentation of any changes made by any predecessor Licensee. Licensee
51b4315fc7SSascha Wildner * must include a prominent statement that the modification is derived,
52b4315fc7SSascha Wildner * directly or indirectly, from Original Intel Code.
53b4315fc7SSascha Wildner *
54b4315fc7SSascha Wildner * 3.2. Redistribution of Source with no Rights to Further Distribute Source.
55b4315fc7SSascha Wildner * Redistribution of source code of any substantial portion of the Covered
56b4315fc7SSascha Wildner * Code or modification without rights to further distribute source must
57b4315fc7SSascha Wildner * include the following Disclaimer and Export Compliance provision in the
58b4315fc7SSascha Wildner * documentation and/or other materials provided with distribution. In
59b4315fc7SSascha Wildner * addition, Licensee may not authorize further sublicense of source of any
60b4315fc7SSascha Wildner * portion of the Covered Code, and must include terms to the effect that the
61b4315fc7SSascha Wildner * license from Licensee to its licensee is limited to the intellectual
62b4315fc7SSascha Wildner * property embodied in the software Licensee provides to its licensee, and
63b4315fc7SSascha Wildner * not to intellectual property embodied in modifications its licensee may
64b4315fc7SSascha Wildner * make.
65b4315fc7SSascha Wildner *
66b4315fc7SSascha Wildner * 3.3. Redistribution of Executable. Redistribution in executable form of any
67b4315fc7SSascha Wildner * substantial portion of the Covered Code or modification must reproduce the
68b4315fc7SSascha Wildner * above Copyright Notice, and the following Disclaimer and Export Compliance
69b4315fc7SSascha Wildner * provision in the documentation and/or other materials provided with the
70b4315fc7SSascha Wildner * distribution.
71b4315fc7SSascha Wildner *
72b4315fc7SSascha Wildner * 3.4. Intel retains all right, title, and interest in and to the Original
73b4315fc7SSascha Wildner * Intel Code.
74b4315fc7SSascha Wildner *
75b4315fc7SSascha Wildner * 3.5. Neither the name Intel nor any other trademark owned or controlled by
76b4315fc7SSascha Wildner * Intel shall be used in advertising or otherwise to promote the sale, use or
77b4315fc7SSascha Wildner * other dealings in products derived from or relating to the Covered Code
78b4315fc7SSascha Wildner * without prior written authorization from Intel.
79b4315fc7SSascha Wildner *
80b4315fc7SSascha Wildner * 4. Disclaimer and Export Compliance
81b4315fc7SSascha Wildner *
82b4315fc7SSascha Wildner * 4.1. INTEL MAKES NO WARRANTY OF ANY KIND REGARDING ANY SOFTWARE PROVIDED
83b4315fc7SSascha Wildner * HERE. ANY SOFTWARE ORIGINATING FROM INTEL OR DERIVED FROM INTEL SOFTWARE
84b4315fc7SSascha Wildner * IS PROVIDED "AS IS," AND INTEL WILL NOT PROVIDE ANY SUPPORT, ASSISTANCE,
85b4315fc7SSascha Wildner * INSTALLATION, TRAINING OR OTHER SERVICES. INTEL WILL NOT PROVIDE ANY
86b4315fc7SSascha Wildner * UPDATES, ENHANCEMENTS OR EXTENSIONS. INTEL SPECIFICALLY DISCLAIMS ANY
87b4315fc7SSascha Wildner * IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT AND FITNESS FOR A
88b4315fc7SSascha Wildner * PARTICULAR PURPOSE.
89b4315fc7SSascha Wildner *
90b4315fc7SSascha Wildner * 4.2. IN NO EVENT SHALL INTEL HAVE ANY LIABILITY TO LICENSEE, ITS LICENSEES
91b4315fc7SSascha Wildner * OR ANY OTHER THIRD PARTY, FOR ANY LOST PROFITS, LOST DATA, LOSS OF USE OR
92b4315fc7SSascha Wildner * COSTS OF PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY INDIRECT,
93b4315fc7SSascha Wildner * SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THIS AGREEMENT, UNDER ANY
94b4315fc7SSascha Wildner * CAUSE OF ACTION OR THEORY OF LIABILITY, AND IRRESPECTIVE OF WHETHER INTEL
95b4315fc7SSascha Wildner * HAS ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. THESE LIMITATIONS
96b4315fc7SSascha Wildner * SHALL APPLY NOTWITHSTANDING THE FAILURE OF THE ESSENTIAL PURPOSE OF ANY
97b4315fc7SSascha Wildner * LIMITED REMEDY.
98b4315fc7SSascha Wildner *
99b4315fc7SSascha Wildner * 4.3. Licensee shall not export, either directly or indirectly, any of this
100b4315fc7SSascha Wildner * software or system incorporating such software without first obtaining any
101b4315fc7SSascha Wildner * required license or other approval from the U. S. Department of Commerce or
102b4315fc7SSascha Wildner * any other agency or department of the United States Government. In the
103b4315fc7SSascha Wildner * event Licensee exports any such software from the United States or
104b4315fc7SSascha Wildner * re-exports any such software from a foreign destination, Licensee shall
105b4315fc7SSascha Wildner * ensure that the distribution and export/re-export of the software is in
106b4315fc7SSascha Wildner * compliance with all laws, regulations, orders, or other restrictions of the
107b4315fc7SSascha Wildner * U.S. Export Administration Regulations. Licensee agrees that neither it nor
108b4315fc7SSascha Wildner * any of its subsidiaries will export/re-export any technical data, process,
109b4315fc7SSascha Wildner * software, or service, directly or indirectly, to any country for which the
110b4315fc7SSascha Wildner * United States government or any agency thereof requires an export license,
111b4315fc7SSascha Wildner * other governmental approval, or letter of assurance, without first obtaining
112b4315fc7SSascha Wildner * such license, approval or letter.
113b4315fc7SSascha Wildner *
114b4315fc7SSascha Wildner *****************************************************************************
115b4315fc7SSascha Wildner *
116b4315fc7SSascha Wildner * Alternatively, you may choose to be licensed under the terms of the
117b4315fc7SSascha Wildner * following license:
118b4315fc7SSascha Wildner *
1190d02842fSSascha Wildner * Redistribution and use in source and binary forms, with or without
1200d02842fSSascha Wildner * modification, are permitted provided that the following conditions
1210d02842fSSascha Wildner * are met:
1220d02842fSSascha Wildner * 1. Redistributions of source code must retain the above copyright
1230d02842fSSascha Wildner * notice, this list of conditions, and the following disclaimer,
1240d02842fSSascha Wildner * without modification.
1250d02842fSSascha Wildner * 2. Redistributions in binary form must reproduce at minimum a disclaimer
1260d02842fSSascha Wildner * substantially similar to the "NO WARRANTY" disclaimer below
1270d02842fSSascha Wildner * ("Disclaimer") and any redistribution must be conditioned upon
1280d02842fSSascha Wildner * including a substantially similar Disclaimer requirement for further
1290d02842fSSascha Wildner * binary redistribution.
1300d02842fSSascha Wildner * 3. Neither the names of the above-listed copyright holders nor the names
1310d02842fSSascha Wildner * of any contributors may be used to endorse or promote products derived
1320d02842fSSascha Wildner * from this software without specific prior written permission.
1330d02842fSSascha Wildner *
134b4315fc7SSascha Wildner * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
135b4315fc7SSascha Wildner * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
136b4315fc7SSascha Wildner * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
137b4315fc7SSascha Wildner * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
138b4315fc7SSascha Wildner * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
139b4315fc7SSascha Wildner * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
140b4315fc7SSascha Wildner * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
141b4315fc7SSascha Wildner * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
142b4315fc7SSascha Wildner * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
143b4315fc7SSascha Wildner * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
144b4315fc7SSascha Wildner * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
145b4315fc7SSascha Wildner *
146b4315fc7SSascha Wildner * Alternatively, you may choose to be licensed under the terms of the
1470d02842fSSascha Wildner * GNU General Public License ("GPL") version 2 as published by the Free
1480d02842fSSascha Wildner * Software Foundation.
1490d02842fSSascha Wildner *
150b4315fc7SSascha Wildner *****************************************************************************/
1510d02842fSSascha Wildner
1520d02842fSSascha Wildner #include "acpi.h"
1530d02842fSSascha Wildner #include "accommon.h"
1540d02842fSSascha Wildner #include "acdispat.h"
1550d02842fSSascha Wildner #include "acinterp.h"
1560d02842fSSascha Wildner #include "acnamesp.h"
1576a0135c2SSascha Wildner #include "acparser.h"
1586a0135c2SSascha Wildner #include "amlcode.h"
159267c04fdSSascha Wildner #include "acdebug.h"
1600d02842fSSascha Wildner
1610d02842fSSascha Wildner
1620d02842fSSascha Wildner #define _COMPONENT ACPI_DISPATCHER
1630d02842fSSascha Wildner ACPI_MODULE_NAME ("dsmethod")
1640d02842fSSascha Wildner
1650d02842fSSascha Wildner /* Local prototypes */
1660d02842fSSascha Wildner
1670d02842fSSascha Wildner static ACPI_STATUS
1686a0135c2SSascha Wildner AcpiDsDetectNamedOpcodes (
1696a0135c2SSascha Wildner ACPI_WALK_STATE *WalkState,
1706a0135c2SSascha Wildner ACPI_PARSE_OBJECT **OutOp);
1716a0135c2SSascha Wildner
1726a0135c2SSascha Wildner static ACPI_STATUS
1730d02842fSSascha Wildner AcpiDsCreateMethodMutex (
1740d02842fSSascha Wildner ACPI_OPERAND_OBJECT *MethodDesc);
1750d02842fSSascha Wildner
1760d02842fSSascha Wildner
1770d02842fSSascha Wildner /*******************************************************************************
1780d02842fSSascha Wildner *
1796a0135c2SSascha Wildner * FUNCTION: AcpiDsAutoSerializeMethod
1806a0135c2SSascha Wildner *
1816a0135c2SSascha Wildner * PARAMETERS: Node - Namespace Node of the method
1826a0135c2SSascha Wildner * ObjDesc - Method object attached to node
1836a0135c2SSascha Wildner *
1846a0135c2SSascha Wildner * RETURN: Status
1856a0135c2SSascha Wildner *
1866a0135c2SSascha Wildner * DESCRIPTION: Parse a control method AML to scan for control methods that
1876a0135c2SSascha Wildner * need serialization due to the creation of named objects.
1886a0135c2SSascha Wildner *
1896a0135c2SSascha Wildner * NOTE: It is a bit of overkill to mark all such methods serialized, since
1906a0135c2SSascha Wildner * there is only a problem if the method actually blocks during execution.
1916a0135c2SSascha Wildner * A blocking operation is, for example, a Sleep() operation, or any access
1926a0135c2SSascha Wildner * to an operation region. However, it is probably not possible to easily
1936a0135c2SSascha Wildner * detect whether a method will block or not, so we simply mark all suspicious
1946a0135c2SSascha Wildner * methods as serialized.
1956a0135c2SSascha Wildner *
1966a0135c2SSascha Wildner * NOTE2: This code is essentially a generic routine for parsing a single
1976a0135c2SSascha Wildner * control method.
1986a0135c2SSascha Wildner *
1996a0135c2SSascha Wildner ******************************************************************************/
2006a0135c2SSascha Wildner
2016a0135c2SSascha Wildner ACPI_STATUS
AcpiDsAutoSerializeMethod(ACPI_NAMESPACE_NODE * Node,ACPI_OPERAND_OBJECT * ObjDesc)2026a0135c2SSascha Wildner AcpiDsAutoSerializeMethod (
2036a0135c2SSascha Wildner ACPI_NAMESPACE_NODE *Node,
2046a0135c2SSascha Wildner ACPI_OPERAND_OBJECT *ObjDesc)
2056a0135c2SSascha Wildner {
2066a0135c2SSascha Wildner ACPI_STATUS Status;
2076a0135c2SSascha Wildner ACPI_PARSE_OBJECT *Op = NULL;
2086a0135c2SSascha Wildner ACPI_WALK_STATE *WalkState;
2096a0135c2SSascha Wildner
2106a0135c2SSascha Wildner
2116a0135c2SSascha Wildner ACPI_FUNCTION_TRACE_PTR (DsAutoSerializeMethod, Node);
2126a0135c2SSascha Wildner
2136a0135c2SSascha Wildner
2146a0135c2SSascha Wildner ACPI_DEBUG_PRINT ((ACPI_DB_PARSE,
2156a0135c2SSascha Wildner "Method auto-serialization parse [%4.4s] %p\n",
2166a0135c2SSascha Wildner AcpiUtGetNodeName (Node), Node));
2176a0135c2SSascha Wildner
2186a0135c2SSascha Wildner /* Create/Init a root op for the method parse tree */
2196a0135c2SSascha Wildner
220267c04fdSSascha Wildner Op = AcpiPsAllocOp (AML_METHOD_OP, ObjDesc->Method.AmlStart);
2216a0135c2SSascha Wildner if (!Op)
2226a0135c2SSascha Wildner {
223a96e04f2SSascha Wildner return_ACPI_STATUS (AE_NO_MEMORY);
2246a0135c2SSascha Wildner }
2256a0135c2SSascha Wildner
2266a0135c2SSascha Wildner AcpiPsSetName (Op, Node->Name.Integer);
2276a0135c2SSascha Wildner Op->Common.Node = Node;
2286a0135c2SSascha Wildner
2296a0135c2SSascha Wildner /* Create and initialize a new walk state */
2306a0135c2SSascha Wildner
2316a0135c2SSascha Wildner WalkState = AcpiDsCreateWalkState (Node->OwnerId, NULL, NULL, NULL);
2326a0135c2SSascha Wildner if (!WalkState)
2336a0135c2SSascha Wildner {
234896f2e3aSSascha Wildner AcpiPsFreeOp (Op);
235a96e04f2SSascha Wildner return_ACPI_STATUS (AE_NO_MEMORY);
2366a0135c2SSascha Wildner }
2376a0135c2SSascha Wildner
238820c5b08SSascha Wildner Status = AcpiDsInitAmlWalk (WalkState, Op, Node,
239820c5b08SSascha Wildner ObjDesc->Method.AmlStart, ObjDesc->Method.AmlLength, NULL, 0);
2406a0135c2SSascha Wildner if (ACPI_FAILURE (Status))
2416a0135c2SSascha Wildner {
2426a0135c2SSascha Wildner AcpiDsDeleteWalkState (WalkState);
243896f2e3aSSascha Wildner AcpiPsFreeOp (Op);
2446a0135c2SSascha Wildner return_ACPI_STATUS (Status);
2456a0135c2SSascha Wildner }
2466a0135c2SSascha Wildner
2476a0135c2SSascha Wildner WalkState->DescendingCallback = AcpiDsDetectNamedOpcodes;
2486a0135c2SSascha Wildner
2496a0135c2SSascha Wildner /* Parse the method, scan for creation of named objects */
2506a0135c2SSascha Wildner
2516a0135c2SSascha Wildner Status = AcpiPsParseAml (WalkState);
2526a0135c2SSascha Wildner
2536a0135c2SSascha Wildner AcpiPsDeleteParseTree (Op);
2546a0135c2SSascha Wildner return_ACPI_STATUS (Status);
2556a0135c2SSascha Wildner }
2566a0135c2SSascha Wildner
2576a0135c2SSascha Wildner
2586a0135c2SSascha Wildner /*******************************************************************************
2596a0135c2SSascha Wildner *
2606a0135c2SSascha Wildner * FUNCTION: AcpiDsDetectNamedOpcodes
2616a0135c2SSascha Wildner *
2626a0135c2SSascha Wildner * PARAMETERS: WalkState - Current state of the parse tree walk
2636a0135c2SSascha Wildner * OutOp - Unused, required for parser interface
2646a0135c2SSascha Wildner *
2656a0135c2SSascha Wildner * RETURN: Status
2666a0135c2SSascha Wildner *
2676a0135c2SSascha Wildner * DESCRIPTION: Descending callback used during the loading of ACPI tables.
2686a0135c2SSascha Wildner * Currently used to detect methods that must be marked serialized
2696a0135c2SSascha Wildner * in order to avoid problems with the creation of named objects.
2706a0135c2SSascha Wildner *
2716a0135c2SSascha Wildner ******************************************************************************/
2726a0135c2SSascha Wildner
2736a0135c2SSascha Wildner static ACPI_STATUS
AcpiDsDetectNamedOpcodes(ACPI_WALK_STATE * WalkState,ACPI_PARSE_OBJECT ** OutOp)2746a0135c2SSascha Wildner AcpiDsDetectNamedOpcodes (
2756a0135c2SSascha Wildner ACPI_WALK_STATE *WalkState,
2766a0135c2SSascha Wildner ACPI_PARSE_OBJECT **OutOp)
2776a0135c2SSascha Wildner {
2786a0135c2SSascha Wildner
2796a0135c2SSascha Wildner ACPI_FUNCTION_NAME (AcpiDsDetectNamedOpcodes);
2806a0135c2SSascha Wildner
2816a0135c2SSascha Wildner
2826a0135c2SSascha Wildner /* We are only interested in opcodes that create a new name */
2836a0135c2SSascha Wildner
2846a0135c2SSascha Wildner if (!(WalkState->OpInfo->Flags & (AML_NAMED | AML_CREATE | AML_FIELD)))
2856a0135c2SSascha Wildner {
2866a0135c2SSascha Wildner return (AE_OK);
2876a0135c2SSascha Wildner }
2886a0135c2SSascha Wildner
2896a0135c2SSascha Wildner /*
2906a0135c2SSascha Wildner * At this point, we know we have a Named object opcode.
2916a0135c2SSascha Wildner * Mark the method as serialized. Later code will create a mutex for
2926a0135c2SSascha Wildner * this method to enforce serialization.
293d4972a9cSSascha Wildner *
294d4972a9cSSascha Wildner * Note, ACPI_METHOD_IGNORE_SYNC_LEVEL flag means that we will ignore the
295d4972a9cSSascha Wildner * Sync Level mechanism for this method, even though it is now serialized.
296d4972a9cSSascha Wildner * Otherwise, there can be conflicts with existing ASL code that actually
297d4972a9cSSascha Wildner * uses sync levels.
2986a0135c2SSascha Wildner */
299d4972a9cSSascha Wildner WalkState->MethodDesc->Method.SyncLevel = 0;
300d4972a9cSSascha Wildner WalkState->MethodDesc->Method.InfoFlags |=
301d4972a9cSSascha Wildner (ACPI_METHOD_SERIALIZED | ACPI_METHOD_IGNORE_SYNC_LEVEL);
3026a0135c2SSascha Wildner
3036a0135c2SSascha Wildner ACPI_DEBUG_PRINT ((ACPI_DB_INFO,
3046a0135c2SSascha Wildner "Method serialized [%4.4s] %p - [%s] (%4.4X)\n",
3056a0135c2SSascha Wildner WalkState->MethodNode->Name.Ascii, WalkState->MethodNode,
3066a0135c2SSascha Wildner WalkState->OpInfo->Name, WalkState->Opcode));
3076a0135c2SSascha Wildner
3086a0135c2SSascha Wildner /* Abort the parse, no need to examine this method any further */
3096a0135c2SSascha Wildner
3106a0135c2SSascha Wildner return (AE_CTRL_TERMINATE);
3116a0135c2SSascha Wildner }
3126a0135c2SSascha Wildner
3136a0135c2SSascha Wildner
3146a0135c2SSascha Wildner /*******************************************************************************
3156a0135c2SSascha Wildner *
3160d02842fSSascha Wildner * FUNCTION: AcpiDsMethodError
3170d02842fSSascha Wildner *
3180d02842fSSascha Wildner * PARAMETERS: Status - Execution status
3190d02842fSSascha Wildner * WalkState - Current state
3200d02842fSSascha Wildner *
3210d02842fSSascha Wildner * RETURN: Status
3220d02842fSSascha Wildner *
3230d02842fSSascha Wildner * DESCRIPTION: Called on method error. Invoke the global exception handler if
324267c04fdSSascha Wildner * present, dump the method data if the debugger is configured
3250d02842fSSascha Wildner *
3260d02842fSSascha Wildner * Note: Allows the exception handler to change the status code
3270d02842fSSascha Wildner *
3280d02842fSSascha Wildner ******************************************************************************/
3290d02842fSSascha Wildner
3300d02842fSSascha Wildner ACPI_STATUS
AcpiDsMethodError(ACPI_STATUS Status,ACPI_WALK_STATE * WalkState)3310d02842fSSascha Wildner AcpiDsMethodError (
3320d02842fSSascha Wildner ACPI_STATUS Status,
3330d02842fSSascha Wildner ACPI_WALK_STATE *WalkState)
3340d02842fSSascha Wildner {
335267c04fdSSascha Wildner UINT32 AmlOffset;
3361093ca81SSascha Wildner ACPI_NAME Name = 0;
337267c04fdSSascha Wildner
338267c04fdSSascha Wildner
3390d02842fSSascha Wildner ACPI_FUNCTION_ENTRY ();
3400d02842fSSascha Wildner
3410d02842fSSascha Wildner
3420d02842fSSascha Wildner /* Ignore AE_OK and control exception codes */
3430d02842fSSascha Wildner
3440d02842fSSascha Wildner if (ACPI_SUCCESS (Status) ||
3450d02842fSSascha Wildner (Status & AE_CODE_CONTROL))
3460d02842fSSascha Wildner {
3470d02842fSSascha Wildner return (Status);
3480d02842fSSascha Wildner }
3490d02842fSSascha Wildner
3500d02842fSSascha Wildner /* Invoke the global exception handler */
3510d02842fSSascha Wildner
3520d02842fSSascha Wildner if (AcpiGbl_ExceptionHandler)
3530d02842fSSascha Wildner {
3540d02842fSSascha Wildner /* Exit the interpreter, allow handler to execute methods */
3550d02842fSSascha Wildner
3560d02842fSSascha Wildner AcpiExExitInterpreter ();
3570d02842fSSascha Wildner
3580d02842fSSascha Wildner /*
3590d02842fSSascha Wildner * Handler can map the exception code to anything it wants, including
3600d02842fSSascha Wildner * AE_OK, in which case the executing method will not be aborted.
3610d02842fSSascha Wildner */
362267c04fdSSascha Wildner AmlOffset = (UINT32) ACPI_PTR_DIFF (WalkState->Aml,
363267c04fdSSascha Wildner WalkState->ParserState.AmlStart);
364267c04fdSSascha Wildner
3651093ca81SSascha Wildner if (WalkState->MethodNode)
3661093ca81SSascha Wildner {
3671093ca81SSascha Wildner Name = WalkState->MethodNode->Name.Integer;
3681093ca81SSascha Wildner }
3691093ca81SSascha Wildner else if (WalkState->DeferredNode)
3701093ca81SSascha Wildner {
3711093ca81SSascha Wildner Name = WalkState->DeferredNode->Name.Integer;
3721093ca81SSascha Wildner }
3731093ca81SSascha Wildner
3741093ca81SSascha Wildner Status = AcpiGbl_ExceptionHandler (Status, Name,
375267c04fdSSascha Wildner WalkState->Opcode, AmlOffset, NULL);
3760d02842fSSascha Wildner AcpiExEnterInterpreter ();
3770d02842fSSascha Wildner }
3780d02842fSSascha Wildner
3790d02842fSSascha Wildner AcpiDsClearImplicitReturn (WalkState);
3800d02842fSSascha Wildner
3810d02842fSSascha Wildner if (ACPI_FAILURE (Status))
3820d02842fSSascha Wildner {
383267c04fdSSascha Wildner AcpiDsDumpMethodStack (Status, WalkState, WalkState->Op);
3840d02842fSSascha Wildner
385267c04fdSSascha Wildner /* Display method locals/args if debugger is present */
386267c04fdSSascha Wildner
387267c04fdSSascha Wildner #ifdef ACPI_DEBUGGER
388267c04fdSSascha Wildner AcpiDbDumpMethodInfo (Status, WalkState);
3890d02842fSSascha Wildner #endif
390267c04fdSSascha Wildner }
3910d02842fSSascha Wildner
3920d02842fSSascha Wildner return (Status);
3930d02842fSSascha Wildner }
3940d02842fSSascha Wildner
3950d02842fSSascha Wildner
3960d02842fSSascha Wildner /*******************************************************************************
3970d02842fSSascha Wildner *
3980d02842fSSascha Wildner * FUNCTION: AcpiDsCreateMethodMutex
3990d02842fSSascha Wildner *
4000d02842fSSascha Wildner * PARAMETERS: ObjDesc - The method object
4010d02842fSSascha Wildner *
4020d02842fSSascha Wildner * RETURN: Status
4030d02842fSSascha Wildner *
4040d02842fSSascha Wildner * DESCRIPTION: Create a mutex object for a serialized control method
4050d02842fSSascha Wildner *
4060d02842fSSascha Wildner ******************************************************************************/
4070d02842fSSascha Wildner
4080d02842fSSascha Wildner static ACPI_STATUS
AcpiDsCreateMethodMutex(ACPI_OPERAND_OBJECT * MethodDesc)4090d02842fSSascha Wildner AcpiDsCreateMethodMutex (
4100d02842fSSascha Wildner ACPI_OPERAND_OBJECT *MethodDesc)
4110d02842fSSascha Wildner {
4120d02842fSSascha Wildner ACPI_OPERAND_OBJECT *MutexDesc;
4130d02842fSSascha Wildner ACPI_STATUS Status;
4140d02842fSSascha Wildner
4150d02842fSSascha Wildner
4160d02842fSSascha Wildner ACPI_FUNCTION_TRACE (DsCreateMethodMutex);
4170d02842fSSascha Wildner
4180d02842fSSascha Wildner
4190d02842fSSascha Wildner /* Create the new mutex object */
4200d02842fSSascha Wildner
4210d02842fSSascha Wildner MutexDesc = AcpiUtCreateInternalObject (ACPI_TYPE_MUTEX);
4220d02842fSSascha Wildner if (!MutexDesc)
4230d02842fSSascha Wildner {
4240d02842fSSascha Wildner return_ACPI_STATUS (AE_NO_MEMORY);
4250d02842fSSascha Wildner }
4260d02842fSSascha Wildner
4270d02842fSSascha Wildner /* Create the actual OS Mutex */
4280d02842fSSascha Wildner
4290d02842fSSascha Wildner Status = AcpiOsCreateMutex (&MutexDesc->Mutex.OsMutex);
4300d02842fSSascha Wildner if (ACPI_FAILURE (Status))
4310d02842fSSascha Wildner {
4320d02842fSSascha Wildner AcpiUtDeleteObjectDesc (MutexDesc);
4330d02842fSSascha Wildner return_ACPI_STATUS (Status);
4340d02842fSSascha Wildner }
4350d02842fSSascha Wildner
4360d02842fSSascha Wildner MutexDesc->Mutex.SyncLevel = MethodDesc->Method.SyncLevel;
4370d02842fSSascha Wildner MethodDesc->Method.Mutex = MutexDesc;
4380d02842fSSascha Wildner return_ACPI_STATUS (AE_OK);
4390d02842fSSascha Wildner }
4400d02842fSSascha Wildner
4410d02842fSSascha Wildner
4420d02842fSSascha Wildner /*******************************************************************************
4430d02842fSSascha Wildner *
4440d02842fSSascha Wildner * FUNCTION: AcpiDsBeginMethodExecution
4450d02842fSSascha Wildner *
4460d02842fSSascha Wildner * PARAMETERS: MethodNode - Node of the method
4470d02842fSSascha Wildner * ObjDesc - The method object
4480d02842fSSascha Wildner * WalkState - current state, NULL if not yet executing
4490d02842fSSascha Wildner * a method.
4500d02842fSSascha Wildner *
4510d02842fSSascha Wildner * RETURN: Status
4520d02842fSSascha Wildner *
4530d02842fSSascha Wildner * DESCRIPTION: Prepare a method for execution. Parses the method if necessary,
4540d02842fSSascha Wildner * increments the thread count, and waits at the method semaphore
4550d02842fSSascha Wildner * for clearance to execute.
4560d02842fSSascha Wildner *
4570d02842fSSascha Wildner ******************************************************************************/
4580d02842fSSascha Wildner
4590d02842fSSascha Wildner ACPI_STATUS
AcpiDsBeginMethodExecution(ACPI_NAMESPACE_NODE * MethodNode,ACPI_OPERAND_OBJECT * ObjDesc,ACPI_WALK_STATE * WalkState)4600d02842fSSascha Wildner AcpiDsBeginMethodExecution (
4610d02842fSSascha Wildner ACPI_NAMESPACE_NODE *MethodNode,
4620d02842fSSascha Wildner ACPI_OPERAND_OBJECT *ObjDesc,
4630d02842fSSascha Wildner ACPI_WALK_STATE *WalkState)
4640d02842fSSascha Wildner {
4650d02842fSSascha Wildner ACPI_STATUS Status = AE_OK;
4660d02842fSSascha Wildner
4670d02842fSSascha Wildner
4680d02842fSSascha Wildner ACPI_FUNCTION_TRACE_PTR (DsBeginMethodExecution, MethodNode);
4690d02842fSSascha Wildner
4700d02842fSSascha Wildner
4710d02842fSSascha Wildner if (!MethodNode)
4720d02842fSSascha Wildner {
4730d02842fSSascha Wildner return_ACPI_STATUS (AE_NULL_ENTRY);
4740d02842fSSascha Wildner }
4750d02842fSSascha Wildner
476267c04fdSSascha Wildner AcpiExStartTraceMethod (MethodNode, ObjDesc, WalkState);
477267c04fdSSascha Wildner
4780d02842fSSascha Wildner /* Prevent wraparound of thread count */
4790d02842fSSascha Wildner
4800d02842fSSascha Wildner if (ObjDesc->Method.ThreadCount == ACPI_UINT8_MAX)
4810d02842fSSascha Wildner {
4820d02842fSSascha Wildner ACPI_ERROR ((AE_INFO,
4830d02842fSSascha Wildner "Method reached maximum reentrancy limit (255)"));
4840d02842fSSascha Wildner return_ACPI_STATUS (AE_AML_METHOD_LIMIT);
4850d02842fSSascha Wildner }
4860d02842fSSascha Wildner
4870d02842fSSascha Wildner /*
4880d02842fSSascha Wildner * If this method is serialized, we need to acquire the method mutex.
4890d02842fSSascha Wildner */
4900d02842fSSascha Wildner if (ObjDesc->Method.InfoFlags & ACPI_METHOD_SERIALIZED)
4910d02842fSSascha Wildner {
4920d02842fSSascha Wildner /*
4930d02842fSSascha Wildner * Create a mutex for the method if it is defined to be Serialized
4940d02842fSSascha Wildner * and a mutex has not already been created. We defer the mutex creation
4950d02842fSSascha Wildner * until a method is actually executed, to minimize the object count
4960d02842fSSascha Wildner */
4970d02842fSSascha Wildner if (!ObjDesc->Method.Mutex)
4980d02842fSSascha Wildner {
4990d02842fSSascha Wildner Status = AcpiDsCreateMethodMutex (ObjDesc);
5000d02842fSSascha Wildner if (ACPI_FAILURE (Status))
5010d02842fSSascha Wildner {
5020d02842fSSascha Wildner return_ACPI_STATUS (Status);
5030d02842fSSascha Wildner }
5040d02842fSSascha Wildner }
5050d02842fSSascha Wildner
5060d02842fSSascha Wildner /*
5070d02842fSSascha Wildner * The CurrentSyncLevel (per-thread) must be less than or equal to
5080d02842fSSascha Wildner * the sync level of the method. This mechanism provides some
509d4972a9cSSascha Wildner * deadlock prevention.
510d4972a9cSSascha Wildner *
511d4972a9cSSascha Wildner * If the method was auto-serialized, we just ignore the sync level
512d4972a9cSSascha Wildner * mechanism, because auto-serialization of methods can interfere
513d4972a9cSSascha Wildner * with ASL code that actually uses sync levels.
5140d02842fSSascha Wildner *
5150d02842fSSascha Wildner * Top-level method invocation has no walk state at this point
5160d02842fSSascha Wildner */
5170d02842fSSascha Wildner if (WalkState &&
518d4972a9cSSascha Wildner (!(ObjDesc->Method.InfoFlags & ACPI_METHOD_IGNORE_SYNC_LEVEL)) &&
519820c5b08SSascha Wildner (WalkState->Thread->CurrentSyncLevel >
520820c5b08SSascha Wildner ObjDesc->Method.Mutex->Mutex.SyncLevel))
5210d02842fSSascha Wildner {
5220d02842fSSascha Wildner ACPI_ERROR ((AE_INFO,
523820c5b08SSascha Wildner "Cannot acquire Mutex for method [%4.4s]"
524820c5b08SSascha Wildner ", current SyncLevel is too large (%u)",
5250d02842fSSascha Wildner AcpiUtGetNodeName (MethodNode),
5260d02842fSSascha Wildner WalkState->Thread->CurrentSyncLevel));
5270d02842fSSascha Wildner
5280d02842fSSascha Wildner return_ACPI_STATUS (AE_AML_MUTEX_ORDER);
5290d02842fSSascha Wildner }
5300d02842fSSascha Wildner
5310d02842fSSascha Wildner /*
5320d02842fSSascha Wildner * Obtain the method mutex if necessary. Do not acquire mutex for a
5330d02842fSSascha Wildner * recursive call.
5340d02842fSSascha Wildner */
5350d02842fSSascha Wildner if (!WalkState ||
5360d02842fSSascha Wildner !ObjDesc->Method.Mutex->Mutex.ThreadId ||
537820c5b08SSascha Wildner (WalkState->Thread->ThreadId !=
538820c5b08SSascha Wildner ObjDesc->Method.Mutex->Mutex.ThreadId))
5390d02842fSSascha Wildner {
5400d02842fSSascha Wildner /*
5410d02842fSSascha Wildner * Acquire the method mutex. This releases the interpreter if we
5420d02842fSSascha Wildner * block (and reacquires it before it returns)
5430d02842fSSascha Wildner */
544820c5b08SSascha Wildner Status = AcpiExSystemWaitMutex (
545820c5b08SSascha Wildner ObjDesc->Method.Mutex->Mutex.OsMutex, ACPI_WAIT_FOREVER);
5460d02842fSSascha Wildner if (ACPI_FAILURE (Status))
5470d02842fSSascha Wildner {
5480d02842fSSascha Wildner return_ACPI_STATUS (Status);
5490d02842fSSascha Wildner }
5500d02842fSSascha Wildner
5510d02842fSSascha Wildner /* Update the mutex and walk info and save the original SyncLevel */
5520d02842fSSascha Wildner
5530d02842fSSascha Wildner if (WalkState)
5540d02842fSSascha Wildner {
5550d02842fSSascha Wildner ObjDesc->Method.Mutex->Mutex.OriginalSyncLevel =
5560d02842fSSascha Wildner WalkState->Thread->CurrentSyncLevel;
5570d02842fSSascha Wildner
558820c5b08SSascha Wildner ObjDesc->Method.Mutex->Mutex.ThreadId =
559820c5b08SSascha Wildner WalkState->Thread->ThreadId;
560820c5b08SSascha Wildner
561820c5b08SSascha Wildner /*
562820c5b08SSascha Wildner * Update the current SyncLevel only if this is not an auto-
563820c5b08SSascha Wildner * serialized method. In the auto case, we have to ignore
564820c5b08SSascha Wildner * the sync level for the method mutex (created for the
565820c5b08SSascha Wildner * auto-serialization) because we have no idea of what the
566820c5b08SSascha Wildner * sync level should be. Therefore, just ignore it.
567820c5b08SSascha Wildner */
568820c5b08SSascha Wildner if (!(ObjDesc->Method.InfoFlags &
569820c5b08SSascha Wildner ACPI_METHOD_IGNORE_SYNC_LEVEL))
570820c5b08SSascha Wildner {
571820c5b08SSascha Wildner WalkState->Thread->CurrentSyncLevel =
572820c5b08SSascha Wildner ObjDesc->Method.SyncLevel;
573820c5b08SSascha Wildner }
5740d02842fSSascha Wildner }
5750d02842fSSascha Wildner else
5760d02842fSSascha Wildner {
5770d02842fSSascha Wildner ObjDesc->Method.Mutex->Mutex.OriginalSyncLevel =
5780d02842fSSascha Wildner ObjDesc->Method.Mutex->Mutex.SyncLevel;
5790d27ae55SSascha Wildner
5800d27ae55SSascha Wildner ObjDesc->Method.Mutex->Mutex.ThreadId =
5810d27ae55SSascha Wildner AcpiOsGetThreadId ();
5820d02842fSSascha Wildner }
5830d02842fSSascha Wildner }
5840d02842fSSascha Wildner
5850d02842fSSascha Wildner /* Always increase acquisition depth */
5860d02842fSSascha Wildner
5870d02842fSSascha Wildner ObjDesc->Method.Mutex->Mutex.AcquisitionDepth++;
5880d02842fSSascha Wildner }
5890d02842fSSascha Wildner
5900d02842fSSascha Wildner /*
5910d02842fSSascha Wildner * Allocate an Owner ID for this method, only if this is the first thread
5920d02842fSSascha Wildner * to begin concurrent execution. We only need one OwnerId, even if the
5930d02842fSSascha Wildner * method is invoked recursively.
5940d02842fSSascha Wildner */
5950d02842fSSascha Wildner if (!ObjDesc->Method.OwnerId)
5960d02842fSSascha Wildner {
5970d02842fSSascha Wildner Status = AcpiUtAllocateOwnerId (&ObjDesc->Method.OwnerId);
5980d02842fSSascha Wildner if (ACPI_FAILURE (Status))
5990d02842fSSascha Wildner {
6000d02842fSSascha Wildner goto Cleanup;
6010d02842fSSascha Wildner }
6020d02842fSSascha Wildner }
6030d02842fSSascha Wildner
6040d02842fSSascha Wildner /*
6050d02842fSSascha Wildner * Increment the method parse tree thread count since it has been
6060d02842fSSascha Wildner * reentered one more time (even if it is the same thread)
6070d02842fSSascha Wildner */
6080d02842fSSascha Wildner ObjDesc->Method.ThreadCount++;
6090d02842fSSascha Wildner AcpiMethodCount++;
6100d02842fSSascha Wildner return_ACPI_STATUS (Status);
6110d02842fSSascha Wildner
6120d02842fSSascha Wildner
6130d02842fSSascha Wildner Cleanup:
6140d02842fSSascha Wildner /* On error, must release the method mutex (if present) */
6150d02842fSSascha Wildner
6160d02842fSSascha Wildner if (ObjDesc->Method.Mutex)
6170d02842fSSascha Wildner {
6180d02842fSSascha Wildner AcpiOsReleaseMutex (ObjDesc->Method.Mutex->Mutex.OsMutex);
6190d02842fSSascha Wildner }
6200d02842fSSascha Wildner return_ACPI_STATUS (Status);
6210d02842fSSascha Wildner }
6220d02842fSSascha Wildner
6230d02842fSSascha Wildner
6240d02842fSSascha Wildner /*******************************************************************************
6250d02842fSSascha Wildner *
6260d02842fSSascha Wildner * FUNCTION: AcpiDsCallControlMethod
6270d02842fSSascha Wildner *
6280d02842fSSascha Wildner * PARAMETERS: Thread - Info for this thread
6290d02842fSSascha Wildner * ThisWalkState - Current walk state
6300d02842fSSascha Wildner * Op - Current Op to be walked
6310d02842fSSascha Wildner *
6320d02842fSSascha Wildner * RETURN: Status
6330d02842fSSascha Wildner *
6340d02842fSSascha Wildner * DESCRIPTION: Transfer execution to a called control method
6350d02842fSSascha Wildner *
6360d02842fSSascha Wildner ******************************************************************************/
6370d02842fSSascha Wildner
6380d02842fSSascha Wildner ACPI_STATUS
AcpiDsCallControlMethod(ACPI_THREAD_STATE * Thread,ACPI_WALK_STATE * ThisWalkState,ACPI_PARSE_OBJECT * Op)6390d02842fSSascha Wildner AcpiDsCallControlMethod (
6400d02842fSSascha Wildner ACPI_THREAD_STATE *Thread,
6410d02842fSSascha Wildner ACPI_WALK_STATE *ThisWalkState,
6420d02842fSSascha Wildner ACPI_PARSE_OBJECT *Op)
6430d02842fSSascha Wildner {
6440d02842fSSascha Wildner ACPI_STATUS Status;
6450d02842fSSascha Wildner ACPI_NAMESPACE_NODE *MethodNode;
6460d02842fSSascha Wildner ACPI_WALK_STATE *NextWalkState = NULL;
6470d02842fSSascha Wildner ACPI_OPERAND_OBJECT *ObjDesc;
6480d02842fSSascha Wildner ACPI_EVALUATE_INFO *Info;
6490d02842fSSascha Wildner UINT32 i;
6500d02842fSSascha Wildner
6510d02842fSSascha Wildner
6520d02842fSSascha Wildner ACPI_FUNCTION_TRACE_PTR (DsCallControlMethod, ThisWalkState);
6530d02842fSSascha Wildner
654820c5b08SSascha Wildner ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
655820c5b08SSascha Wildner "Calling method %p, currentstate=%p\n",
6560d02842fSSascha Wildner ThisWalkState->PrevOp, ThisWalkState));
6570d02842fSSascha Wildner
6580d02842fSSascha Wildner /*
6590d02842fSSascha Wildner * Get the namespace entry for the control method we are about to call
6600d02842fSSascha Wildner */
6610d02842fSSascha Wildner MethodNode = ThisWalkState->MethodCallNode;
6620d02842fSSascha Wildner if (!MethodNode)
6630d02842fSSascha Wildner {
6640d02842fSSascha Wildner return_ACPI_STATUS (AE_NULL_ENTRY);
6650d02842fSSascha Wildner }
6660d02842fSSascha Wildner
6670d02842fSSascha Wildner ObjDesc = AcpiNsGetAttachedObject (MethodNode);
6680d02842fSSascha Wildner if (!ObjDesc)
6690d02842fSSascha Wildner {
6700d02842fSSascha Wildner return_ACPI_STATUS (AE_NULL_OBJECT);
6710d02842fSSascha Wildner }
6720d02842fSSascha Wildner
6730d02842fSSascha Wildner /* Init for new method, possibly wait on method mutex */
6740d02842fSSascha Wildner
675820c5b08SSascha Wildner Status = AcpiDsBeginMethodExecution (
676820c5b08SSascha Wildner MethodNode, ObjDesc, ThisWalkState);
6770d02842fSSascha Wildner if (ACPI_FAILURE (Status))
6780d02842fSSascha Wildner {
6790d02842fSSascha Wildner return_ACPI_STATUS (Status);
6800d02842fSSascha Wildner }
6810d02842fSSascha Wildner
6820d02842fSSascha Wildner /* Begin method parse/execution. Create a new walk state */
6830d02842fSSascha Wildner
684820c5b08SSascha Wildner NextWalkState = AcpiDsCreateWalkState (
685820c5b08SSascha Wildner ObjDesc->Method.OwnerId, NULL, ObjDesc, Thread);
6860d02842fSSascha Wildner if (!NextWalkState)
6870d02842fSSascha Wildner {
6880d02842fSSascha Wildner Status = AE_NO_MEMORY;
6890d02842fSSascha Wildner goto Cleanup;
6900d02842fSSascha Wildner }
6910d02842fSSascha Wildner
6920d02842fSSascha Wildner /*
6930d02842fSSascha Wildner * The resolved arguments were put on the previous walk state's operand
6940d02842fSSascha Wildner * stack. Operands on the previous walk state stack always
6950d02842fSSascha Wildner * start at index 0. Also, null terminate the list of arguments
6960d02842fSSascha Wildner */
6970d02842fSSascha Wildner ThisWalkState->Operands [ThisWalkState->NumOperands] = NULL;
6980d02842fSSascha Wildner
6990d02842fSSascha Wildner /*
7000d02842fSSascha Wildner * Allocate and initialize the evaluation information block
7010d02842fSSascha Wildner * TBD: this is somewhat inefficient, should change interface to
7020d02842fSSascha Wildner * DsInitAmlWalk. For now, keeps this struct off the CPU stack
7030d02842fSSascha Wildner */
7040d02842fSSascha Wildner Info = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_EVALUATE_INFO));
7050d02842fSSascha Wildner if (!Info)
7060d02842fSSascha Wildner {
7070d02842fSSascha Wildner Status = AE_NO_MEMORY;
7080d02842fSSascha Wildner goto Cleanup;
7090d02842fSSascha Wildner }
7100d02842fSSascha Wildner
7110d02842fSSascha Wildner Info->Parameters = &ThisWalkState->Operands[0];
7120d02842fSSascha Wildner
7130d02842fSSascha Wildner Status = AcpiDsInitAmlWalk (NextWalkState, NULL, MethodNode,
7140d02842fSSascha Wildner ObjDesc->Method.AmlStart, ObjDesc->Method.AmlLength,
7150d02842fSSascha Wildner Info, ACPI_IMODE_EXECUTE);
7160d02842fSSascha Wildner
7170d02842fSSascha Wildner ACPI_FREE (Info);
7180d02842fSSascha Wildner if (ACPI_FAILURE (Status))
7190d02842fSSascha Wildner {
7200d02842fSSascha Wildner goto Cleanup;
7210d02842fSSascha Wildner }
7220d02842fSSascha Wildner
723ef944814SSascha Wildner NextWalkState->MethodNestingDepth = ThisWalkState->MethodNestingDepth + 1;
724ef944814SSascha Wildner
7250d02842fSSascha Wildner /*
7260d02842fSSascha Wildner * Delete the operands on the previous walkstate operand stack
7270d02842fSSascha Wildner * (they were copied to new objects)
7280d02842fSSascha Wildner */
7290d02842fSSascha Wildner for (i = 0; i < ObjDesc->Method.ParamCount; i++)
7300d02842fSSascha Wildner {
7310d02842fSSascha Wildner AcpiUtRemoveReference (ThisWalkState->Operands [i]);
7320d02842fSSascha Wildner ThisWalkState->Operands [i] = NULL;
7330d02842fSSascha Wildner }
7340d02842fSSascha Wildner
7350d02842fSSascha Wildner /* Clear the operand stack */
7360d02842fSSascha Wildner
7370d02842fSSascha Wildner ThisWalkState->NumOperands = 0;
7380d02842fSSascha Wildner
7390d02842fSSascha Wildner ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
7400d02842fSSascha Wildner "**** Begin nested execution of [%4.4s] **** WalkState=%p\n",
7410d02842fSSascha Wildner MethodNode->Name.Ascii, NextWalkState));
7420d02842fSSascha Wildner
743ef944814SSascha Wildner ThisWalkState->MethodPathname = AcpiNsGetNormalizedPathname (MethodNode, TRUE);
744ef944814SSascha Wildner ThisWalkState->MethodIsNested = TRUE;
745ef944814SSascha Wildner
746ef944814SSascha Wildner /* Optional object evaluation log */
747ef944814SSascha Wildner
748ef944814SSascha Wildner ACPI_DEBUG_PRINT_RAW ((ACPI_DB_EVALUATION,
749ef944814SSascha Wildner "%-26s: %*s%s\n", " Nested method call",
750ef944814SSascha Wildner NextWalkState->MethodNestingDepth * 3, " ",
751ef944814SSascha Wildner &ThisWalkState->MethodPathname[1]));
752ef944814SSascha Wildner
7530d02842fSSascha Wildner /* Invoke an internal method if necessary */
7540d02842fSSascha Wildner
7550d02842fSSascha Wildner if (ObjDesc->Method.InfoFlags & ACPI_METHOD_INTERNAL_ONLY)
7560d02842fSSascha Wildner {
7570d02842fSSascha Wildner Status = ObjDesc->Method.Dispatch.Implementation (NextWalkState);
7580d02842fSSascha Wildner if (Status == AE_OK)
7590d02842fSSascha Wildner {
7600d02842fSSascha Wildner Status = AE_CTRL_TERMINATE;
7610d02842fSSascha Wildner }
7620d02842fSSascha Wildner }
7630d02842fSSascha Wildner
7640d02842fSSascha Wildner return_ACPI_STATUS (Status);
7650d02842fSSascha Wildner
7660d02842fSSascha Wildner
7670d02842fSSascha Wildner Cleanup:
7680d02842fSSascha Wildner
7690d02842fSSascha Wildner /* On error, we must terminate the method properly */
7700d02842fSSascha Wildner
7710d02842fSSascha Wildner AcpiDsTerminateControlMethod (ObjDesc, NextWalkState);
7720d02842fSSascha Wildner AcpiDsDeleteWalkState (NextWalkState);
7730d02842fSSascha Wildner
7740d02842fSSascha Wildner return_ACPI_STATUS (Status);
7750d02842fSSascha Wildner }
7760d02842fSSascha Wildner
7770d02842fSSascha Wildner
7780d02842fSSascha Wildner /*******************************************************************************
7790d02842fSSascha Wildner *
7800d02842fSSascha Wildner * FUNCTION: AcpiDsRestartControlMethod
7810d02842fSSascha Wildner *
7820d02842fSSascha Wildner * PARAMETERS: WalkState - State for preempted method (caller)
7830d02842fSSascha Wildner * ReturnDesc - Return value from the called method
7840d02842fSSascha Wildner *
7850d02842fSSascha Wildner * RETURN: Status
7860d02842fSSascha Wildner *
7870d02842fSSascha Wildner * DESCRIPTION: Restart a method that was preempted by another (nested) method
7880d02842fSSascha Wildner * invocation. Handle the return value (if any) from the callee.
7890d02842fSSascha Wildner *
7900d02842fSSascha Wildner ******************************************************************************/
7910d02842fSSascha Wildner
7920d02842fSSascha Wildner ACPI_STATUS
AcpiDsRestartControlMethod(ACPI_WALK_STATE * WalkState,ACPI_OPERAND_OBJECT * ReturnDesc)7930d02842fSSascha Wildner AcpiDsRestartControlMethod (
7940d02842fSSascha Wildner ACPI_WALK_STATE *WalkState,
7950d02842fSSascha Wildner ACPI_OPERAND_OBJECT *ReturnDesc)
7960d02842fSSascha Wildner {
7970d02842fSSascha Wildner ACPI_STATUS Status;
7980d02842fSSascha Wildner int SameAsImplicitReturn;
7990d02842fSSascha Wildner
8000d02842fSSascha Wildner
8010d02842fSSascha Wildner ACPI_FUNCTION_TRACE_PTR (DsRestartControlMethod, WalkState);
8020d02842fSSascha Wildner
8030d02842fSSascha Wildner
8040d02842fSSascha Wildner ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
8050d02842fSSascha Wildner "****Restart [%4.4s] Op %p ReturnValueFromCallee %p\n",
8060d02842fSSascha Wildner AcpiUtGetNodeName (WalkState->MethodNode),
8070d02842fSSascha Wildner WalkState->MethodCallOp, ReturnDesc));
8080d02842fSSascha Wildner
8090d02842fSSascha Wildner ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
8100d02842fSSascha Wildner " ReturnFromThisMethodUsed?=%X ResStack %p Walk %p\n",
8110d02842fSSascha Wildner WalkState->ReturnUsed,
8120d02842fSSascha Wildner WalkState->Results, WalkState));
8130d02842fSSascha Wildner
8140d02842fSSascha Wildner /* Did the called method return a value? */
8150d02842fSSascha Wildner
8160d02842fSSascha Wildner if (ReturnDesc)
8170d02842fSSascha Wildner {
8180d02842fSSascha Wildner /* Is the implicit return object the same as the return desc? */
8190d02842fSSascha Wildner
8200d02842fSSascha Wildner SameAsImplicitReturn = (WalkState->ImplicitReturnObj == ReturnDesc);
8210d02842fSSascha Wildner
8220d02842fSSascha Wildner /* Are we actually going to use the return value? */
8230d02842fSSascha Wildner
8240d02842fSSascha Wildner if (WalkState->ReturnUsed)
8250d02842fSSascha Wildner {
8260d02842fSSascha Wildner /* Save the return value from the previous method */
8270d02842fSSascha Wildner
8280d02842fSSascha Wildner Status = AcpiDsResultPush (ReturnDesc, WalkState);
8290d02842fSSascha Wildner if (ACPI_FAILURE (Status))
8300d02842fSSascha Wildner {
8310d02842fSSascha Wildner AcpiUtRemoveReference (ReturnDesc);
8320d02842fSSascha Wildner return_ACPI_STATUS (Status);
8330d02842fSSascha Wildner }
8340d02842fSSascha Wildner
8350d02842fSSascha Wildner /*
8360d02842fSSascha Wildner * Save as THIS method's return value in case it is returned
8370d02842fSSascha Wildner * immediately to yet another method
8380d02842fSSascha Wildner */
8390d02842fSSascha Wildner WalkState->ReturnDesc = ReturnDesc;
8400d02842fSSascha Wildner }
8410d02842fSSascha Wildner
8420d02842fSSascha Wildner /*
8430d02842fSSascha Wildner * The following code is the optional support for the so-called
8440d02842fSSascha Wildner * "implicit return". Some AML code assumes that the last value of the
8450d02842fSSascha Wildner * method is "implicitly" returned to the caller, in the absence of an
8460d02842fSSascha Wildner * explicit return value.
8470d02842fSSascha Wildner *
8480d02842fSSascha Wildner * Just save the last result of the method as the return value.
8490d02842fSSascha Wildner *
8500d02842fSSascha Wildner * NOTE: this is optional because the ASL language does not actually
8510d02842fSSascha Wildner * support this behavior.
8520d02842fSSascha Wildner */
8530d02842fSSascha Wildner else if (!AcpiDsDoImplicitReturn (ReturnDesc, WalkState, FALSE) ||
8540d02842fSSascha Wildner SameAsImplicitReturn)
8550d02842fSSascha Wildner {
8560d02842fSSascha Wildner /*
8570d02842fSSascha Wildner * Delete the return value if it will not be used by the
8580d02842fSSascha Wildner * calling method or remove one reference if the explicit return
8590d02842fSSascha Wildner * is the same as the implicit return value.
8600d02842fSSascha Wildner */
8610d02842fSSascha Wildner AcpiUtRemoveReference (ReturnDesc);
8620d02842fSSascha Wildner }
8630d02842fSSascha Wildner }
8640d02842fSSascha Wildner
8650d02842fSSascha Wildner return_ACPI_STATUS (AE_OK);
8660d02842fSSascha Wildner }
8670d02842fSSascha Wildner
8680d02842fSSascha Wildner
8690d02842fSSascha Wildner /*******************************************************************************
8700d02842fSSascha Wildner *
8710d02842fSSascha Wildner * FUNCTION: AcpiDsTerminateControlMethod
8720d02842fSSascha Wildner *
8730d02842fSSascha Wildner * PARAMETERS: MethodDesc - Method object
8740d02842fSSascha Wildner * WalkState - State associated with the method
8750d02842fSSascha Wildner *
8760d02842fSSascha Wildner * RETURN: None
8770d02842fSSascha Wildner *
8780d02842fSSascha Wildner * DESCRIPTION: Terminate a control method. Delete everything that the method
8790d02842fSSascha Wildner * created, delete all locals and arguments, and delete the parse
8800d02842fSSascha Wildner * tree if requested.
8810d02842fSSascha Wildner *
8820d02842fSSascha Wildner * MUTEX: Interpreter is locked
8830d02842fSSascha Wildner *
8840d02842fSSascha Wildner ******************************************************************************/
8850d02842fSSascha Wildner
8860d02842fSSascha Wildner void
AcpiDsTerminateControlMethod(ACPI_OPERAND_OBJECT * MethodDesc,ACPI_WALK_STATE * WalkState)8870d02842fSSascha Wildner AcpiDsTerminateControlMethod (
8880d02842fSSascha Wildner ACPI_OPERAND_OBJECT *MethodDesc,
8890d02842fSSascha Wildner ACPI_WALK_STATE *WalkState)
8900d02842fSSascha Wildner {
8910d02842fSSascha Wildner
8920d02842fSSascha Wildner ACPI_FUNCTION_TRACE_PTR (DsTerminateControlMethod, WalkState);
8930d02842fSSascha Wildner
8940d02842fSSascha Wildner
8950d02842fSSascha Wildner /* MethodDesc is required, WalkState is optional */
8960d02842fSSascha Wildner
8970d02842fSSascha Wildner if (!MethodDesc)
8980d02842fSSascha Wildner {
8990d02842fSSascha Wildner return_VOID;
9000d02842fSSascha Wildner }
9010d02842fSSascha Wildner
9020d02842fSSascha Wildner if (WalkState)
9030d02842fSSascha Wildner {
9040d02842fSSascha Wildner /* Delete all arguments and locals */
9050d02842fSSascha Wildner
9060d02842fSSascha Wildner AcpiDsMethodDataDeleteAll (WalkState);
9070d02842fSSascha Wildner
9080d02842fSSascha Wildner /*
9090d02842fSSascha Wildner * Delete any namespace objects created anywhere within the
9100d02842fSSascha Wildner * namespace by the execution of this method. Unless:
9110d02842fSSascha Wildner * 1) This method is a module-level executable code method, in which
9120d02842fSSascha Wildner * case we want make the objects permanent.
9130d02842fSSascha Wildner * 2) There are other threads executing the method, in which case we
9140d02842fSSascha Wildner * will wait until the last thread has completed.
9150d02842fSSascha Wildner */
9160d02842fSSascha Wildner if (!(MethodDesc->Method.InfoFlags & ACPI_METHOD_MODULE_LEVEL) &&
9170d02842fSSascha Wildner (MethodDesc->Method.ThreadCount == 1))
9180d02842fSSascha Wildner {
9190d02842fSSascha Wildner /* Delete any direct children of (created by) this method */
9200d02842fSSascha Wildner
921e5e174adSSascha Wildner (void) AcpiExExitInterpreter ();
9220d02842fSSascha Wildner AcpiNsDeleteNamespaceSubtree (WalkState->MethodNode);
923e5e174adSSascha Wildner (void) AcpiExEnterInterpreter ();
9240d02842fSSascha Wildner
9250d02842fSSascha Wildner /*
9260d02842fSSascha Wildner * Delete any objects that were created by this method
9270d02842fSSascha Wildner * elsewhere in the namespace (if any were created).
9280d02842fSSascha Wildner * Use of the ACPI_METHOD_MODIFIED_NAMESPACE optimizes the
9290d02842fSSascha Wildner * deletion such that we don't have to perform an entire
9300d02842fSSascha Wildner * namespace walk for every control method execution.
9310d02842fSSascha Wildner */
9320d02842fSSascha Wildner if (MethodDesc->Method.InfoFlags & ACPI_METHOD_MODIFIED_NAMESPACE)
9330d02842fSSascha Wildner {
934e5e174adSSascha Wildner (void) AcpiExExitInterpreter ();
9350d02842fSSascha Wildner AcpiNsDeleteNamespaceByOwner (MethodDesc->Method.OwnerId);
936e5e174adSSascha Wildner (void) AcpiExEnterInterpreter ();
937820c5b08SSascha Wildner MethodDesc->Method.InfoFlags &=
938820c5b08SSascha Wildner ~ACPI_METHOD_MODIFIED_NAMESPACE;
9390d02842fSSascha Wildner }
9400d02842fSSascha Wildner }
941a96e04f2SSascha Wildner
942a96e04f2SSascha Wildner /*
943a96e04f2SSascha Wildner * If method is serialized, release the mutex and restore the
944a96e04f2SSascha Wildner * current sync level for this thread
945a96e04f2SSascha Wildner */
946a96e04f2SSascha Wildner if (MethodDesc->Method.Mutex)
947a96e04f2SSascha Wildner {
948a96e04f2SSascha Wildner /* Acquisition Depth handles recursive calls */
949a96e04f2SSascha Wildner
950a96e04f2SSascha Wildner MethodDesc->Method.Mutex->Mutex.AcquisitionDepth--;
951a96e04f2SSascha Wildner if (!MethodDesc->Method.Mutex->Mutex.AcquisitionDepth)
952a96e04f2SSascha Wildner {
953a96e04f2SSascha Wildner WalkState->Thread->CurrentSyncLevel =
954a96e04f2SSascha Wildner MethodDesc->Method.Mutex->Mutex.OriginalSyncLevel;
955a96e04f2SSascha Wildner
956a96e04f2SSascha Wildner AcpiOsReleaseMutex (
957a96e04f2SSascha Wildner MethodDesc->Method.Mutex->Mutex.OsMutex);
958a96e04f2SSascha Wildner MethodDesc->Method.Mutex->Mutex.ThreadId = 0;
959a96e04f2SSascha Wildner }
960a96e04f2SSascha Wildner }
9610d02842fSSascha Wildner }
9620d02842fSSascha Wildner
9630d02842fSSascha Wildner /* Decrement the thread count on the method */
9640d02842fSSascha Wildner
9650d02842fSSascha Wildner if (MethodDesc->Method.ThreadCount)
9660d02842fSSascha Wildner {
9670d02842fSSascha Wildner MethodDesc->Method.ThreadCount--;
9680d02842fSSascha Wildner }
9690d02842fSSascha Wildner else
9700d02842fSSascha Wildner {
9710d02842fSSascha Wildner ACPI_ERROR ((AE_INFO,
9720d02842fSSascha Wildner "Invalid zero thread count in method"));
9730d02842fSSascha Wildner }
9740d02842fSSascha Wildner
9750d02842fSSascha Wildner /* Are there any other threads currently executing this method? */
9760d02842fSSascha Wildner
9770d02842fSSascha Wildner if (MethodDesc->Method.ThreadCount)
9780d02842fSSascha Wildner {
9790d02842fSSascha Wildner /*
9800d02842fSSascha Wildner * Additional threads. Do not release the OwnerId in this case,
9810d02842fSSascha Wildner * we immediately reuse it for the next thread executing this method
9820d02842fSSascha Wildner */
9830d02842fSSascha Wildner ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
9840d02842fSSascha Wildner "*** Completed execution of one thread, %u threads remaining\n",
9850d02842fSSascha Wildner MethodDesc->Method.ThreadCount));
9860d02842fSSascha Wildner }
9870d02842fSSascha Wildner else
9880d02842fSSascha Wildner {
9890d02842fSSascha Wildner /* This is the only executing thread for this method */
9900d02842fSSascha Wildner
9910d02842fSSascha Wildner /*
9920d02842fSSascha Wildner * Support to dynamically change a method from NotSerialized to
9930d02842fSSascha Wildner * Serialized if it appears that the method is incorrectly written and
9940d02842fSSascha Wildner * does not support multiple thread execution. The best example of this
9950d02842fSSascha Wildner * is if such a method creates namespace objects and blocks. A second
9960d02842fSSascha Wildner * thread will fail with an AE_ALREADY_EXISTS exception.
9970d02842fSSascha Wildner *
9980d02842fSSascha Wildner * This code is here because we must wait until the last thread exits
9990d02842fSSascha Wildner * before marking the method as serialized.
10000d02842fSSascha Wildner */
10010d02842fSSascha Wildner if (MethodDesc->Method.InfoFlags & ACPI_METHOD_SERIALIZED_PENDING)
10020d02842fSSascha Wildner {
10030d02842fSSascha Wildner if (WalkState)
10040d02842fSSascha Wildner {
10057c9678bcSSascha Wildner ACPI_INFO ((
1006820c5b08SSascha Wildner "Marking method %4.4s as Serialized "
1007820c5b08SSascha Wildner "because of AE_ALREADY_EXISTS error",
10080d02842fSSascha Wildner WalkState->MethodNode->Name.Ascii));
10090d02842fSSascha Wildner }
10100d02842fSSascha Wildner
10110d02842fSSascha Wildner /*
10120d02842fSSascha Wildner * Method tried to create an object twice and was marked as
10130d02842fSSascha Wildner * "pending serialized". The probable cause is that the method
10140d02842fSSascha Wildner * cannot handle reentrancy.
10150d02842fSSascha Wildner *
10160d02842fSSascha Wildner * The method was created as NotSerialized, but it tried to create
10170d02842fSSascha Wildner * a named object and then blocked, causing the second thread
10180d02842fSSascha Wildner * entrance to begin and then fail. Workaround this problem by
10190d02842fSSascha Wildner * marking the method permanently as Serialized when the last
10200d02842fSSascha Wildner * thread exits here.
10210d02842fSSascha Wildner */
1022820c5b08SSascha Wildner MethodDesc->Method.InfoFlags &=
1023820c5b08SSascha Wildner ~ACPI_METHOD_SERIALIZED_PENDING;
1024820c5b08SSascha Wildner
1025d4972a9cSSascha Wildner MethodDesc->Method.InfoFlags |=
1026d4972a9cSSascha Wildner (ACPI_METHOD_SERIALIZED | ACPI_METHOD_IGNORE_SYNC_LEVEL);
10270d02842fSSascha Wildner MethodDesc->Method.SyncLevel = 0;
10280d02842fSSascha Wildner }
10290d02842fSSascha Wildner
10300d02842fSSascha Wildner /* No more threads, we can free the OwnerId */
10310d02842fSSascha Wildner
10320d02842fSSascha Wildner if (!(MethodDesc->Method.InfoFlags & ACPI_METHOD_MODULE_LEVEL))
10330d02842fSSascha Wildner {
10340d02842fSSascha Wildner AcpiUtReleaseOwnerId (&MethodDesc->Method.OwnerId);
10350d02842fSSascha Wildner }
10360d02842fSSascha Wildner }
10370d02842fSSascha Wildner
1038267c04fdSSascha Wildner AcpiExStopTraceMethod ((ACPI_NAMESPACE_NODE *) MethodDesc->Method.Node,
1039267c04fdSSascha Wildner MethodDesc, WalkState);
1040267c04fdSSascha Wildner
10410d02842fSSascha Wildner return_VOID;
10420d02842fSSascha Wildner }
1043