xref: /titanic_44/usr/src/uts/intel/io/acpica/dispatcher/dscontrol.c (revision 5fd03bc0f2e00e7ba02316c2e08f45d52aab15db)
1 /******************************************************************************
2  *
3  * Module Name: dscontrol - Support for execution control opcodes -
4  *                          if/else/while/return
5  *
6  *****************************************************************************/
7 
8 /*
9  * Copyright (C) 2000 - 2011, Intel Corp.
10  * All rights reserved.
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted provided that the following conditions
14  * are met:
15  * 1. Redistributions of source code must retain the above copyright
16  *    notice, this list of conditions, and the following disclaimer,
17  *    without modification.
18  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
19  *    substantially similar to the "NO WARRANTY" disclaimer below
20  *    ("Disclaimer") and any redistribution must be conditioned upon
21  *    including a substantially similar Disclaimer requirement for further
22  *    binary redistribution.
23  * 3. Neither the names of the above-listed copyright holders nor the names
24  *    of any contributors may be used to endorse or promote products derived
25  *    from this software without specific prior written permission.
26  *
27  * Alternatively, this software may be distributed under the terms of the
28  * GNU General Public License ("GPL") version 2 as published by the Free
29  * Software Foundation.
30  *
31  * NO WARRANTY
32  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
33  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
34  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
35  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
36  * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
37  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
38  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
39  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
40  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
41  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
42  * POSSIBILITY OF SUCH DAMAGES.
43  */
44 
45 #define __DSCONTROL_C__
46 
47 #include "acpi.h"
48 #include "accommon.h"
49 #include "amlcode.h"
50 #include "acdispat.h"
51 #include "acinterp.h"
52 
53 #define _COMPONENT          ACPI_DISPATCHER
54         ACPI_MODULE_NAME    ("dscontrol")
55 
56 
57 /*******************************************************************************
58  *
59  * FUNCTION:    AcpiDsExecBeginControlOp
60  *
61  * PARAMETERS:  WalkList        - The list that owns the walk stack
62  *              Op              - The control Op
63  *
64  * RETURN:      Status
65  *
66  * DESCRIPTION: Handles all control ops encountered during control method
67  *              execution.
68  *
69  ******************************************************************************/
70 
71 ACPI_STATUS
72 AcpiDsExecBeginControlOp (
73     ACPI_WALK_STATE         *WalkState,
74     ACPI_PARSE_OBJECT       *Op)
75 {
76     ACPI_STATUS             Status = AE_OK;
77     ACPI_GENERIC_STATE      *ControlState;
78 
79 
80     ACPI_FUNCTION_NAME (DsExecBeginControlOp);
81 
82 
83     ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "Op=%p Opcode=%2.2X State=%p\n",
84         Op, Op->Common.AmlOpcode, WalkState));
85 
86     switch (Op->Common.AmlOpcode)
87     {
88     case AML_WHILE_OP:
89 
90         /*
91          * If this is an additional iteration of a while loop, continue.
92          * There is no need to allocate a new control state.
93          */
94         if (WalkState->ControlState)
95         {
96             if (WalkState->ControlState->Control.AmlPredicateStart ==
97                 (WalkState->ParserState.Aml - 1))
98             {
99                 /* Reset the state to start-of-loop */
100 
101                 WalkState->ControlState->Common.State =
102                     ACPI_CONTROL_CONDITIONAL_EXECUTING;
103                 break;
104             }
105         }
106 
107         /*lint -fallthrough */
108 
109     case AML_IF_OP:
110 
111         /*
112          * IF/WHILE: Create a new control state to manage these
113          * constructs. We need to manage these as a stack, in order
114          * to handle nesting.
115          */
116         ControlState = AcpiUtCreateControlState ();
117         if (!ControlState)
118         {
119             Status = AE_NO_MEMORY;
120             break;
121         }
122         /*
123          * Save a pointer to the predicate for multiple executions
124          * of a loop
125          */
126         ControlState->Control.AmlPredicateStart = WalkState->ParserState.Aml - 1;
127         ControlState->Control.PackageEnd = WalkState->ParserState.PkgEnd;
128         ControlState->Control.Opcode = Op->Common.AmlOpcode;
129 
130 
131         /* Push the control state on this walk's control stack */
132 
133         AcpiUtPushGenericState (&WalkState->ControlState, ControlState);
134         break;
135 
136     case AML_ELSE_OP:
137 
138         /* Predicate is in the state object */
139         /* If predicate is true, the IF was executed, ignore ELSE part */
140 
141         if (WalkState->LastPredicate)
142         {
143             Status = AE_CTRL_TRUE;
144         }
145 
146         break;
147 
148     case AML_RETURN_OP:
149 
150         break;
151 
152     default:
153         break;
154     }
155 
156     return (Status);
157 }
158 
159 
160 /*******************************************************************************
161  *
162  * FUNCTION:    AcpiDsExecEndControlOp
163  *
164  * PARAMETERS:  WalkList        - The list that owns the walk stack
165  *              Op              - The control Op
166  *
167  * RETURN:      Status
168  *
169  * DESCRIPTION: Handles all control ops encountered during control method
170  *              execution.
171  *
172  ******************************************************************************/
173 
174 ACPI_STATUS
175 AcpiDsExecEndControlOp (
176     ACPI_WALK_STATE         *WalkState,
177     ACPI_PARSE_OBJECT       *Op)
178 {
179     ACPI_STATUS             Status = AE_OK;
180     ACPI_GENERIC_STATE      *ControlState;
181 
182 
183     ACPI_FUNCTION_NAME (DsExecEndControlOp);
184 
185 
186     switch (Op->Common.AmlOpcode)
187     {
188     case AML_IF_OP:
189 
190         ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "[IF_OP] Op=%p\n", Op));
191 
192         /*
193          * Save the result of the predicate in case there is an
194          * ELSE to come
195          */
196         WalkState->LastPredicate =
197             (BOOLEAN) WalkState->ControlState->Common.Value;
198 
199         /*
200          * Pop the control state that was created at the start
201          * of the IF and free it
202          */
203         ControlState = AcpiUtPopGenericState (&WalkState->ControlState);
204         AcpiUtDeleteGenericState (ControlState);
205         break;
206 
207 
208     case AML_ELSE_OP:
209 
210         break;
211 
212 
213     case AML_WHILE_OP:
214 
215         ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "[WHILE_OP] Op=%p\n", Op));
216 
217         ControlState = WalkState->ControlState;
218         if (ControlState->Common.Value)
219         {
220             /* Predicate was true, the body of the loop was just executed */
221 
222             /*
223              * This loop counter mechanism allows the interpreter to escape
224              * possibly infinite loops. This can occur in poorly written AML
225              * when the hardware does not respond within a while loop and the
226              * loop does not implement a timeout.
227              */
228             ControlState->Control.LoopCount++;
229             if (ControlState->Control.LoopCount > ACPI_MAX_LOOP_ITERATIONS)
230             {
231                 Status = AE_AML_INFINITE_LOOP;
232                 break;
233             }
234 
235             /*
236              * Go back and evaluate the predicate and maybe execute the loop
237              * another time
238              */
239             Status = AE_CTRL_PENDING;
240             WalkState->AmlLastWhile = ControlState->Control.AmlPredicateStart;
241             break;
242         }
243 
244         /* Predicate was false, terminate this while loop */
245 
246         ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
247             "[WHILE_OP] termination! Op=%p\n",Op));
248 
249         /* Pop this control state and free it */
250 
251         ControlState = AcpiUtPopGenericState (&WalkState->ControlState);
252         AcpiUtDeleteGenericState (ControlState);
253         break;
254 
255 
256     case AML_RETURN_OP:
257 
258         ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
259             "[RETURN_OP] Op=%p Arg=%p\n",Op, Op->Common.Value.Arg));
260 
261         /*
262          * One optional operand -- the return value
263          * It can be either an immediate operand or a result that
264          * has been bubbled up the tree
265          */
266         if (Op->Common.Value.Arg)
267         {
268             /* Since we have a real Return(), delete any implicit return */
269 
270             AcpiDsClearImplicitReturn (WalkState);
271 
272             /* Return statement has an immediate operand */
273 
274             Status = AcpiDsCreateOperands (WalkState, Op->Common.Value.Arg);
275             if (ACPI_FAILURE (Status))
276             {
277                 return (Status);
278             }
279 
280             /*
281              * If value being returned is a Reference (such as
282              * an arg or local), resolve it now because it may
283              * cease to exist at the end of the method.
284              */
285             Status = AcpiExResolveToValue (&WalkState->Operands [0], WalkState);
286             if (ACPI_FAILURE (Status))
287             {
288                 return (Status);
289             }
290 
291             /*
292              * Get the return value and save as the last result
293              * value.  This is the only place where WalkState->ReturnDesc
294              * is set to anything other than zero!
295              */
296             WalkState->ReturnDesc = WalkState->Operands[0];
297         }
298         else if (WalkState->ResultCount)
299         {
300             /* Since we have a real Return(), delete any implicit return */
301 
302             AcpiDsClearImplicitReturn (WalkState);
303 
304             /*
305              * The return value has come from a previous calculation.
306              *
307              * If value being returned is a Reference (such as
308              * an arg or local), resolve it now because it may
309              * cease to exist at the end of the method.
310              *
311              * Allow references created by the Index operator to return
312              * unchanged.
313              */
314             if ((ACPI_GET_DESCRIPTOR_TYPE (WalkState->Results->Results.ObjDesc[0]) == ACPI_DESC_TYPE_OPERAND) &&
315                 ((WalkState->Results->Results.ObjDesc [0])->Common.Type == ACPI_TYPE_LOCAL_REFERENCE) &&
316                 ((WalkState->Results->Results.ObjDesc [0])->Reference.Class != ACPI_REFCLASS_INDEX))
317             {
318                 Status = AcpiExResolveToValue (&WalkState->Results->Results.ObjDesc [0], WalkState);
319                 if (ACPI_FAILURE (Status))
320                 {
321                     return (Status);
322                 }
323             }
324 
325             WalkState->ReturnDesc = WalkState->Results->Results.ObjDesc [0];
326         }
327         else
328         {
329             /* No return operand */
330 
331             if (WalkState->NumOperands)
332             {
333                 AcpiUtRemoveReference (WalkState->Operands [0]);
334             }
335 
336             WalkState->Operands [0]     = NULL;
337             WalkState->NumOperands      = 0;
338             WalkState->ReturnDesc       = NULL;
339         }
340 
341 
342         ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
343             "Completed RETURN_OP State=%p, RetVal=%p\n",
344             WalkState, WalkState->ReturnDesc));
345 
346         /* End the control method execution right now */
347 
348         Status = AE_CTRL_TERMINATE;
349         break;
350 
351 
352     case AML_NOOP_OP:
353 
354         /* Just do nothing! */
355         break;
356 
357 
358     case AML_BREAK_POINT_OP:
359 
360         /*
361          * Set the single-step flag. This will cause the debugger (if present)
362          * to break to the console within the AML debugger at the start of the
363          * next AML instruction.
364          */
365         ACPI_DEBUGGER_EXEC (
366             AcpiGbl_CmSingleStep = TRUE);
367         ACPI_DEBUGGER_EXEC (
368             AcpiOsPrintf ("**break** Executed AML BreakPoint opcode\n"));
369 
370         /* Call to the OSL in case OS wants a piece of the action */
371 
372         Status = AcpiOsSignal (ACPI_SIGNAL_BREAKPOINT,
373                     "Executed AML Breakpoint opcode");
374         break;
375 
376 
377     case AML_BREAK_OP:
378     case AML_CONTINUE_OP: /* ACPI 2.0 */
379 
380 
381         /* Pop and delete control states until we find a while */
382 
383         while (WalkState->ControlState &&
384                 (WalkState->ControlState->Control.Opcode != AML_WHILE_OP))
385         {
386             ControlState = AcpiUtPopGenericState (&WalkState->ControlState);
387             AcpiUtDeleteGenericState (ControlState);
388         }
389 
390         /* No while found? */
391 
392         if (!WalkState->ControlState)
393         {
394             return (AE_AML_NO_WHILE);
395         }
396 
397         /* Was: WalkState->AmlLastWhile = WalkState->ControlState->Control.AmlPredicateStart; */
398 
399         WalkState->AmlLastWhile = WalkState->ControlState->Control.PackageEnd;
400 
401         /* Return status depending on opcode */
402 
403         if (Op->Common.AmlOpcode == AML_BREAK_OP)
404         {
405             Status = AE_CTRL_BREAK;
406         }
407         else
408         {
409             Status = AE_CTRL_CONTINUE;
410         }
411         break;
412 
413 
414     default:
415 
416         ACPI_ERROR ((AE_INFO, "Unknown control opcode=0x%X Op=%p",
417             Op->Common.AmlOpcode, Op));
418 
419         Status = AE_AML_BAD_OPCODE;
420         break;
421     }
422 
423     return (Status);
424 }
425