xref: /dflybsd-src/sys/contrib/dev/acpica/source/components/dispatcher/dsmethod.c (revision 383048aca08c2de51d27aa8638a36982a0d74550)
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