Branch data Line data Source code
1 : : // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
2 : : /******************************************************************************
3 : : *
4 : : * Module Name: dscontrol - Support for execution control opcodes -
5 : : * if/else/while/return
6 : : *
7 : : * Copyright (C) 2000 - 2020, Intel Corp.
8 : : *
9 : : *****************************************************************************/
10 : :
11 : : #include <acpi/acpi.h>
12 : : #include "accommon.h"
13 : : #include "amlcode.h"
14 : : #include "acdispat.h"
15 : : #include "acinterp.h"
16 : : #include "acdebug.h"
17 : :
18 : : #define _COMPONENT ACPI_DISPATCHER
19 : : ACPI_MODULE_NAME("dscontrol")
20 : :
21 : : /*******************************************************************************
22 : : *
23 : : * FUNCTION: acpi_ds_exec_begin_control_op
24 : : *
25 : : * PARAMETERS: walk_list - The list that owns the walk stack
26 : : * op - The control Op
27 : : *
28 : : * RETURN: Status
29 : : *
30 : : * DESCRIPTION: Handles all control ops encountered during control method
31 : : * execution.
32 : : *
33 : : ******************************************************************************/
34 : : acpi_status
35 : 17934 : acpi_ds_exec_begin_control_op(struct acpi_walk_state *walk_state,
36 : : union acpi_parse_object *op)
37 : : {
38 : 17934 : acpi_status status = AE_OK;
39 : 17934 : union acpi_generic_state *control_state;
40 : :
41 : 17934 : ACPI_FUNCTION_NAME(ds_exec_begin_control_op);
42 : :
43 : : ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, "Op=%p Opcode=%2.2X State=%p\n",
44 : 17934 : op, op->common.aml_opcode, walk_state));
45 : :
46 [ + + + + ]: 17934 : switch (op->common.aml_opcode) {
47 : 2709 : case AML_WHILE_OP:
48 : : /*
49 : : * If this is an additional iteration of a while loop, continue.
50 : : * There is no need to allocate a new control state.
51 : : */
52 [ + + ]: 2709 : if (walk_state->control_state) {
53 : 2688 : if (walk_state->control_state->control.
54 : : aml_predicate_start ==
55 [ + - ]: 2688 : (walk_state->parser_state.aml - 1)) {
56 : :
57 : : /* Reset the state to start-of-loop */
58 : :
59 : 2688 : walk_state->control_state->common.state =
60 : : ACPI_CONTROL_CONDITIONAL_EXECUTING;
61 : 2688 : break;
62 : : }
63 : : }
64 : :
65 : : /*lint -fallthrough */
66 : :
67 : : case AML_IF_OP:
68 : : /*
69 : : * IF/WHILE: Create a new control state to manage these
70 : : * constructs. We need to manage these as a stack, in order
71 : : * to handle nesting.
72 : : */
73 : 12453 : control_state = acpi_ut_create_control_state();
74 [ + - ]: 12453 : if (!control_state) {
75 : : status = AE_NO_MEMORY;
76 : : break;
77 : : }
78 : : /*
79 : : * Save a pointer to the predicate for multiple executions
80 : : * of a loop
81 : : */
82 : 12453 : control_state->control.aml_predicate_start =
83 : 12453 : walk_state->parser_state.aml - 1;
84 : 12453 : control_state->control.package_end =
85 : 12453 : walk_state->parser_state.pkg_end;
86 : 12453 : control_state->control.opcode = op->common.aml_opcode;
87 : 12453 : control_state->control.loop_timeout = acpi_os_get_timer() +
88 : 12453 : ((u64)acpi_gbl_max_loop_iterations * ACPI_100NSEC_PER_SEC);
89 : :
90 : : /* Push the control state on this walk's control stack */
91 : :
92 : 12453 : acpi_ut_push_generic_state(&walk_state->control_state,
93 : : control_state);
94 : 12453 : break;
95 : :
96 : 840 : case AML_ELSE_OP:
97 : :
98 : : /* Predicate is in the state object */
99 : : /* If predicate is true, the IF was executed, ignore ELSE part */
100 : :
101 [ + + ]: 840 : if (walk_state->last_predicate) {
102 : 21 : status = AE_CTRL_TRUE;
103 : : }
104 : :
105 : : break;
106 : :
107 : : case AML_RETURN_OP:
108 : :
109 : : break;
110 : :
111 : : default:
112 : :
113 : : break;
114 : : }
115 : :
116 : 17934 : return (status);
117 : : }
118 : :
119 : : /*******************************************************************************
120 : : *
121 : : * FUNCTION: acpi_ds_exec_end_control_op
122 : : *
123 : : * PARAMETERS: walk_list - The list that owns the walk stack
124 : : * op - The control Op
125 : : *
126 : : * RETURN: Status
127 : : *
128 : : * DESCRIPTION: Handles all control ops encountered during control method
129 : : * execution.
130 : : *
131 : : ******************************************************************************/
132 : :
133 : : acpi_status
134 : 17493 : acpi_ds_exec_end_control_op(struct acpi_walk_state *walk_state,
135 : : union acpi_parse_object *op)
136 : : {
137 : 17493 : acpi_status status = AE_OK;
138 : 17493 : union acpi_generic_state *control_state;
139 : :
140 : 17493 : ACPI_FUNCTION_NAME(ds_exec_end_control_op);
141 : :
142 [ + + + - : 17493 : switch (op->common.aml_opcode) {
- - + ]
143 : 12180 : case AML_IF_OP:
144 : :
145 : 12180 : ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, "[IF_OP] Op=%p\n", op));
146 : :
147 : : /*
148 : : * Save the result of the predicate in case there is an
149 : : * ELSE to come
150 : : */
151 : 12180 : walk_state->last_predicate =
152 : 12180 : (u8)walk_state->control_state->common.value;
153 : :
154 : : /*
155 : : * Pop the control state that was created at the start
156 : : * of the IF and free it
157 : : */
158 : 12180 : control_state =
159 : 12180 : acpi_ut_pop_generic_state(&walk_state->control_state);
160 : 12180 : acpi_ut_delete_generic_state(control_state);
161 : 12180 : break;
162 : :
163 : : case AML_ELSE_OP:
164 : :
165 : : break;
166 : :
167 : 2709 : case AML_WHILE_OP:
168 : :
169 : 2709 : ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, "[WHILE_OP] Op=%p\n", op));
170 : :
171 : 2709 : control_state = walk_state->control_state;
172 [ + + ]: 2709 : if (control_state->common.value) {
173 : :
174 : : /* Predicate was true, the body of the loop was just executed */
175 : :
176 : : /*
177 : : * This infinite loop detection mechanism allows the interpreter
178 : : * to escape possibly infinite loops. This can occur in poorly
179 : : * written AML when the hardware does not respond within a while
180 : : * loop and the loop does not implement a timeout.
181 : : */
182 [ + - ]: 2688 : if (ACPI_TIME_AFTER(acpi_os_get_timer(),
183 : : control_state->control.
184 : : loop_timeout)) {
185 : : status = AE_AML_LOOP_TIMEOUT;
186 : : break;
187 : : }
188 : :
189 : : /*
190 : : * Go back and evaluate the predicate and maybe execute the loop
191 : : * another time
192 : : */
193 : 2688 : status = AE_CTRL_PENDING;
194 : 2688 : walk_state->aml_last_while =
195 : 2688 : control_state->control.aml_predicate_start;
196 : 2688 : break;
197 : : }
198 : :
199 : : /* Predicate was false, terminate this while loop */
200 : :
201 : : ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
202 : 21 : "[WHILE_OP] termination! Op=%p\n", op));
203 : :
204 : : /* Pop this control state and free it */
205 : :
206 : 21 : control_state =
207 : 21 : acpi_ut_pop_generic_state(&walk_state->control_state);
208 : 21 : acpi_ut_delete_generic_state(control_state);
209 : 21 : break;
210 : :
211 : 1953 : case AML_RETURN_OP:
212 : :
213 : : ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
214 : : "[RETURN_OP] Op=%p Arg=%p\n", op,
215 : 1953 : op->common.value.arg));
216 : :
217 : : /*
218 : : * One optional operand -- the return value
219 : : * It can be either an immediate operand or a result that
220 : : * has been bubbled up the tree
221 : : */
222 [ + + ]: 1953 : if (op->common.value.arg) {
223 : :
224 : : /* Since we have a real Return(), delete any implicit return */
225 : :
226 : 1365 : acpi_ds_clear_implicit_return(walk_state);
227 : :
228 : : /* Return statement has an immediate operand */
229 : :
230 : 1365 : status =
231 : 1365 : acpi_ds_create_operands(walk_state,
232 : : op->common.value.arg);
233 [ + - ]: 1365 : if (ACPI_FAILURE(status)) {
234 : : return (status);
235 : : }
236 : :
237 : : /*
238 : : * If value being returned is a Reference (such as
239 : : * an arg or local), resolve it now because it may
240 : : * cease to exist at the end of the method.
241 : : */
242 : 1365 : status =
243 : 1365 : acpi_ex_resolve_to_value(&walk_state->operands[0],
244 : : walk_state);
245 [ + - ]: 1365 : if (ACPI_FAILURE(status)) {
246 : : return (status);
247 : : }
248 : :
249 : : /*
250 : : * Get the return value and save as the last result
251 : : * value. This is the only place where walk_state->return_desc
252 : : * is set to anything other than zero!
253 : : */
254 : 1365 : walk_state->return_desc = walk_state->operands[0];
255 [ + - ]: 588 : } else if (walk_state->result_count) {
256 : :
257 : : /* Since we have a real Return(), delete any implicit return */
258 : :
259 : 588 : acpi_ds_clear_implicit_return(walk_state);
260 : :
261 : : /*
262 : : * The return value has come from a previous calculation.
263 : : *
264 : : * If value being returned is a Reference (such as
265 : : * an arg or local), resolve it now because it may
266 : : * cease to exist at the end of the method.
267 : : *
268 : : * Allow references created by the Index operator to return
269 : : * unchanged.
270 : : */
271 [ + - ]: 588 : if ((ACPI_GET_DESCRIPTOR_TYPE
272 : : (walk_state->results->results.obj_desc[0]) ==
273 : : ACPI_DESC_TYPE_OPERAND)
274 : 588 : && ((walk_state->results->results.obj_desc[0])->
275 [ - + ]: 588 : common.type == ACPI_TYPE_LOCAL_REFERENCE)
276 : 0 : && ((walk_state->results->results.obj_desc[0])->
277 [ # # ]: 0 : reference.class != ACPI_REFCLASS_INDEX)) {
278 : 0 : status =
279 : 0 : acpi_ex_resolve_to_value(&walk_state->
280 : : results->results.
281 : : obj_desc[0],
282 : : walk_state);
283 [ # # ]: 0 : if (ACPI_FAILURE(status)) {
284 : : return (status);
285 : : }
286 : : }
287 : :
288 : 588 : walk_state->return_desc =
289 : 588 : walk_state->results->results.obj_desc[0];
290 : : } else {
291 : : /* No return operand */
292 : :
293 [ # # ]: 0 : if (walk_state->num_operands) {
294 : 0 : acpi_ut_remove_reference(walk_state->
295 : : operands[0]);
296 : : }
297 : :
298 : 0 : walk_state->operands[0] = NULL;
299 : 0 : walk_state->num_operands = 0;
300 : 0 : walk_state->return_desc = NULL;
301 : : }
302 : :
303 : : ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
304 : : "Completed RETURN_OP State=%p, RetVal=%p\n",
305 : : walk_state, walk_state->return_desc));
306 : :
307 : : /* End the control method execution right now */
308 : :
309 : : status = AE_CTRL_TERMINATE;
310 : : break;
311 : :
312 : : case AML_NOOP_OP:
313 : :
314 : : /* Just do nothing! */
315 : :
316 : : break;
317 : :
318 : : case AML_BREAKPOINT_OP:
319 : :
320 : 0 : acpi_db_signal_break_point(walk_state);
321 : :
322 : : /* Call to the OSL in case OS wants a piece of the action */
323 : :
324 : 0 : status = acpi_os_signal(ACPI_SIGNAL_BREAKPOINT,
325 : : "Executed AML Breakpoint opcode");
326 : 0 : break;
327 : :
328 : : case AML_BREAK_OP:
329 : : case AML_CONTINUE_OP: /* ACPI 2.0 */
330 : :
331 : : /* Pop and delete control states until we find a while */
332 : :
333 [ # # ]: 0 : while (walk_state->control_state &&
334 [ # # ]: 0 : (walk_state->control_state->control.opcode !=
335 : : AML_WHILE_OP)) {
336 : 0 : control_state =
337 : 0 : acpi_ut_pop_generic_state(&walk_state->
338 : : control_state);
339 : 0 : acpi_ut_delete_generic_state(control_state);
340 : : }
341 : :
342 : : /* No while found? */
343 : :
344 [ # # ]: 0 : if (!walk_state->control_state) {
345 : : return (AE_AML_NO_WHILE);
346 : : }
347 : :
348 : : /* Was: walk_state->aml_last_while = walk_state->control_state->Control.aml_predicate_start; */
349 : :
350 : 0 : walk_state->aml_last_while =
351 : 0 : walk_state->control_state->control.package_end;
352 : :
353 : : /* Return status depending on opcode */
354 : :
355 [ # # ]: 0 : if (op->common.aml_opcode == AML_BREAK_OP) {
356 : : status = AE_CTRL_BREAK;
357 : : } else {
358 : 0 : status = AE_CTRL_CONTINUE;
359 : : }
360 : : break;
361 : :
362 : 0 : default:
363 : :
364 : 0 : ACPI_ERROR((AE_INFO, "Unknown control opcode=0x%X Op=%p",
365 : : op->common.aml_opcode, op));
366 : :
367 : 0 : status = AE_AML_BAD_OPCODE;
368 : 0 : break;
369 : : }
370 : :
371 : : return (status);
372 : : }
|