Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/drivers/acpi/acpica/dscontrol.c
15109 views
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
#include <acpi/acpi.h>
46
#include "accommon.h"
47
#include "amlcode.h"
48
#include "acdispat.h"
49
#include "acinterp.h"
50
51
#define _COMPONENT ACPI_DISPATCHER
52
ACPI_MODULE_NAME("dscontrol")
53
54
/*******************************************************************************
55
*
56
* FUNCTION: acpi_ds_exec_begin_control_op
57
*
58
* PARAMETERS: walk_list - The list that owns the walk stack
59
* Op - The control Op
60
*
61
* RETURN: Status
62
*
63
* DESCRIPTION: Handles all control ops encountered during control method
64
* execution.
65
*
66
******************************************************************************/
67
acpi_status
68
acpi_ds_exec_begin_control_op(struct acpi_walk_state *walk_state,
69
union acpi_parse_object *op)
70
{
71
acpi_status status = AE_OK;
72
union acpi_generic_state *control_state;
73
74
ACPI_FUNCTION_NAME(ds_exec_begin_control_op);
75
76
ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, "Op=%p Opcode=%2.2X State=%p\n",
77
op, op->common.aml_opcode, walk_state));
78
79
switch (op->common.aml_opcode) {
80
case AML_WHILE_OP:
81
82
/*
83
* If this is an additional iteration of a while loop, continue.
84
* There is no need to allocate a new control state.
85
*/
86
if (walk_state->control_state) {
87
if (walk_state->control_state->control.
88
aml_predicate_start ==
89
(walk_state->parser_state.aml - 1)) {
90
91
/* Reset the state to start-of-loop */
92
93
walk_state->control_state->common.state =
94
ACPI_CONTROL_CONDITIONAL_EXECUTING;
95
break;
96
}
97
}
98
99
/*lint -fallthrough */
100
101
case AML_IF_OP:
102
103
/*
104
* IF/WHILE: Create a new control state to manage these
105
* constructs. We need to manage these as a stack, in order
106
* to handle nesting.
107
*/
108
control_state = acpi_ut_create_control_state();
109
if (!control_state) {
110
status = AE_NO_MEMORY;
111
break;
112
}
113
/*
114
* Save a pointer to the predicate for multiple executions
115
* of a loop
116
*/
117
control_state->control.aml_predicate_start =
118
walk_state->parser_state.aml - 1;
119
control_state->control.package_end =
120
walk_state->parser_state.pkg_end;
121
control_state->control.opcode = op->common.aml_opcode;
122
123
/* Push the control state on this walk's control stack */
124
125
acpi_ut_push_generic_state(&walk_state->control_state,
126
control_state);
127
break;
128
129
case AML_ELSE_OP:
130
131
/* Predicate is in the state object */
132
/* If predicate is true, the IF was executed, ignore ELSE part */
133
134
if (walk_state->last_predicate) {
135
status = AE_CTRL_TRUE;
136
}
137
138
break;
139
140
case AML_RETURN_OP:
141
142
break;
143
144
default:
145
break;
146
}
147
148
return (status);
149
}
150
151
/*******************************************************************************
152
*
153
* FUNCTION: acpi_ds_exec_end_control_op
154
*
155
* PARAMETERS: walk_list - The list that owns the walk stack
156
* Op - The control Op
157
*
158
* RETURN: Status
159
*
160
* DESCRIPTION: Handles all control ops encountered during control method
161
* execution.
162
*
163
******************************************************************************/
164
165
acpi_status
166
acpi_ds_exec_end_control_op(struct acpi_walk_state * walk_state,
167
union acpi_parse_object * op)
168
{
169
acpi_status status = AE_OK;
170
union acpi_generic_state *control_state;
171
172
ACPI_FUNCTION_NAME(ds_exec_end_control_op);
173
174
switch (op->common.aml_opcode) {
175
case AML_IF_OP:
176
177
ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, "[IF_OP] Op=%p\n", op));
178
179
/*
180
* Save the result of the predicate in case there is an
181
* ELSE to come
182
*/
183
walk_state->last_predicate =
184
(u8)walk_state->control_state->common.value;
185
186
/*
187
* Pop the control state that was created at the start
188
* of the IF and free it
189
*/
190
control_state =
191
acpi_ut_pop_generic_state(&walk_state->control_state);
192
acpi_ut_delete_generic_state(control_state);
193
break;
194
195
case AML_ELSE_OP:
196
197
break;
198
199
case AML_WHILE_OP:
200
201
ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, "[WHILE_OP] Op=%p\n", op));
202
203
control_state = walk_state->control_state;
204
if (control_state->common.value) {
205
206
/* Predicate was true, the body of the loop was just executed */
207
208
/*
209
* This loop counter mechanism allows the interpreter to escape
210
* possibly infinite loops. This can occur in poorly written AML
211
* when the hardware does not respond within a while loop and the
212
* loop does not implement a timeout.
213
*/
214
control_state->control.loop_count++;
215
if (control_state->control.loop_count >
216
ACPI_MAX_LOOP_ITERATIONS) {
217
status = AE_AML_INFINITE_LOOP;
218
break;
219
}
220
221
/*
222
* Go back and evaluate the predicate and maybe execute the loop
223
* another time
224
*/
225
status = AE_CTRL_PENDING;
226
walk_state->aml_last_while =
227
control_state->control.aml_predicate_start;
228
break;
229
}
230
231
/* Predicate was false, terminate this while loop */
232
233
ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
234
"[WHILE_OP] termination! Op=%p\n", op));
235
236
/* Pop this control state and free it */
237
238
control_state =
239
acpi_ut_pop_generic_state(&walk_state->control_state);
240
acpi_ut_delete_generic_state(control_state);
241
break;
242
243
case AML_RETURN_OP:
244
245
ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
246
"[RETURN_OP] Op=%p Arg=%p\n", op,
247
op->common.value.arg));
248
249
/*
250
* One optional operand -- the return value
251
* It can be either an immediate operand or a result that
252
* has been bubbled up the tree
253
*/
254
if (op->common.value.arg) {
255
256
/* Since we have a real Return(), delete any implicit return */
257
258
acpi_ds_clear_implicit_return(walk_state);
259
260
/* Return statement has an immediate operand */
261
262
status =
263
acpi_ds_create_operands(walk_state,
264
op->common.value.arg);
265
if (ACPI_FAILURE(status)) {
266
return (status);
267
}
268
269
/*
270
* If value being returned is a Reference (such as
271
* an arg or local), resolve it now because it may
272
* cease to exist at the end of the method.
273
*/
274
status =
275
acpi_ex_resolve_to_value(&walk_state->operands[0],
276
walk_state);
277
if (ACPI_FAILURE(status)) {
278
return (status);
279
}
280
281
/*
282
* Get the return value and save as the last result
283
* value. This is the only place where walk_state->return_desc
284
* is set to anything other than zero!
285
*/
286
walk_state->return_desc = walk_state->operands[0];
287
} else if (walk_state->result_count) {
288
289
/* Since we have a real Return(), delete any implicit return */
290
291
acpi_ds_clear_implicit_return(walk_state);
292
293
/*
294
* The return value has come from a previous calculation.
295
*
296
* If value being returned is a Reference (such as
297
* an arg or local), resolve it now because it may
298
* cease to exist at the end of the method.
299
*
300
* Allow references created by the Index operator to return
301
* unchanged.
302
*/
303
if ((ACPI_GET_DESCRIPTOR_TYPE
304
(walk_state->results->results.obj_desc[0]) ==
305
ACPI_DESC_TYPE_OPERAND)
306
&& ((walk_state->results->results.obj_desc[0])->
307
common.type == ACPI_TYPE_LOCAL_REFERENCE)
308
&& ((walk_state->results->results.obj_desc[0])->
309
reference.class != ACPI_REFCLASS_INDEX)) {
310
status =
311
acpi_ex_resolve_to_value(&walk_state->
312
results->results.
313
obj_desc[0],
314
walk_state);
315
if (ACPI_FAILURE(status)) {
316
return (status);
317
}
318
}
319
320
walk_state->return_desc =
321
walk_state->results->results.obj_desc[0];
322
} else {
323
/* No return operand */
324
325
if (walk_state->num_operands) {
326
acpi_ut_remove_reference(walk_state->
327
operands[0]);
328
}
329
330
walk_state->operands[0] = NULL;
331
walk_state->num_operands = 0;
332
walk_state->return_desc = NULL;
333
}
334
335
ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
336
"Completed RETURN_OP State=%p, RetVal=%p\n",
337
walk_state, walk_state->return_desc));
338
339
/* End the control method execution right now */
340
341
status = AE_CTRL_TERMINATE;
342
break;
343
344
case AML_NOOP_OP:
345
346
/* Just do nothing! */
347
break;
348
349
case AML_BREAK_POINT_OP:
350
351
/*
352
* Set the single-step flag. This will cause the debugger (if present)
353
* to break to the console within the AML debugger at the start of the
354
* next AML instruction.
355
*/
356
ACPI_DEBUGGER_EXEC(acpi_gbl_cm_single_step = TRUE);
357
ACPI_DEBUGGER_EXEC(acpi_os_printf
358
("**break** Executed AML BreakPoint opcode\n"));
359
360
/* Call to the OSL in case OS wants a piece of the action */
361
362
status = acpi_os_signal(ACPI_SIGNAL_BREAKPOINT,
363
"Executed AML Breakpoint opcode");
364
break;
365
366
case AML_BREAK_OP:
367
case AML_CONTINUE_OP: /* ACPI 2.0 */
368
369
/* Pop and delete control states until we find a while */
370
371
while (walk_state->control_state &&
372
(walk_state->control_state->control.opcode !=
373
AML_WHILE_OP)) {
374
control_state =
375
acpi_ut_pop_generic_state(&walk_state->
376
control_state);
377
acpi_ut_delete_generic_state(control_state);
378
}
379
380
/* No while found? */
381
382
if (!walk_state->control_state) {
383
return (AE_AML_NO_WHILE);
384
}
385
386
/* Was: walk_state->aml_last_while = walk_state->control_state->Control.aml_predicate_start; */
387
388
walk_state->aml_last_while =
389
walk_state->control_state->control.package_end;
390
391
/* Return status depending on opcode */
392
393
if (op->common.aml_opcode == AML_BREAK_OP) {
394
status = AE_CTRL_BREAK;
395
} else {
396
status = AE_CTRL_CONTINUE;
397
}
398
break;
399
400
default:
401
402
ACPI_ERROR((AE_INFO, "Unknown control opcode=0x%X Op=%p",
403
op->common.aml_opcode, op));
404
405
status = AE_AML_BAD_OPCODE;
406
break;
407
}
408
409
return (status);
410
}
411
412