Branch data Line data Source code
1 : : // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
2 : : /******************************************************************************
3 : : *
4 : : * Module Name: psloop - Main AML parse loop
5 : : *
6 : : * Copyright (C) 2000 - 2020, Intel Corp.
7 : : *
8 : : *****************************************************************************/
9 : :
10 : : /*
11 : : * Parse the AML and build an operation tree as most interpreters, (such as
12 : : * Perl) do. Parsing is done by hand rather than with a YACC generated parser
13 : : * to tightly constrain stack and dynamic memory usage. Parsing is kept
14 : : * flexible and the code fairly compact by parsing based on a list of AML
15 : : * opcode templates in aml_op_info[].
16 : : */
17 : :
18 : : #include <acpi/acpi.h>
19 : : #include "accommon.h"
20 : : #include "acinterp.h"
21 : : #include "acparser.h"
22 : : #include "acdispat.h"
23 : : #include "amlcode.h"
24 : : #include "acconvert.h"
25 : : #include "acnamesp.h"
26 : :
27 : : #define _COMPONENT ACPI_PARSER
28 : : ACPI_MODULE_NAME("psloop")
29 : :
30 : : /* Local prototypes */
31 : : static acpi_status
32 : : acpi_ps_get_arguments(struct acpi_walk_state *walk_state,
33 : : u8 * aml_op_start, union acpi_parse_object *op);
34 : :
35 : : /*******************************************************************************
36 : : *
37 : : * FUNCTION: acpi_ps_get_arguments
38 : : *
39 : : * PARAMETERS: walk_state - Current state
40 : : * aml_op_start - Op start in AML
41 : : * op - Current Op
42 : : *
43 : : * RETURN: Status
44 : : *
45 : : * DESCRIPTION: Get arguments for passed Op.
46 : : *
47 : : ******************************************************************************/
48 : :
49 : : static acpi_status
50 : 249925 : acpi_ps_get_arguments(struct acpi_walk_state *walk_state,
51 : : u8 * aml_op_start, union acpi_parse_object *op)
52 : : {
53 : 249925 : acpi_status status = AE_OK;
54 : 249925 : union acpi_parse_object *arg = NULL;
55 : :
56 : 249925 : ACPI_FUNCTION_TRACE_PTR(ps_get_arguments, walk_state);
57 : :
58 : : ACPI_DEBUG_PRINT((ACPI_DB_PARSE,
59 : : "Get arguments for opcode [%s]\n",
60 : 249925 : op->common.aml_op_name));
61 : :
62 [ + + + ]: 249925 : switch (op->common.aml_opcode) {
63 : 31421 : case AML_BYTE_OP: /* AML_BYTEDATA_ARG */
64 : : case AML_WORD_OP: /* AML_WORDDATA_ARG */
65 : : case AML_DWORD_OP: /* AML_DWORDATA_ARG */
66 : : case AML_QWORD_OP: /* AML_QWORDATA_ARG */
67 : : case AML_STRING_OP: /* AML_ASCIICHARLIST_ARG */
68 : :
69 : : /* Fill in constant or string argument directly */
70 : :
71 : 31421 : acpi_ps_get_next_simple_arg(&(walk_state->parser_state),
72 : 31421 : GET_CURRENT_ARG_TYPE(walk_state->
73 : : arg_types),
74 : : op);
75 : 31421 : break;
76 : :
77 : 6266 : case AML_INT_NAMEPATH_OP: /* AML_NAMESTRING_ARG */
78 : :
79 : 6266 : status = acpi_ps_get_next_namepath(walk_state,
80 : : &(walk_state->parser_state),
81 : : op,
82 : : ACPI_POSSIBLE_METHOD_CALL);
83 [ + - ]: 6266 : if (ACPI_FAILURE(status)) {
84 : : return_ACPI_STATUS(status);
85 : : }
86 : :
87 : 6266 : walk_state->arg_types = 0;
88 : 6266 : break;
89 : :
90 : : default:
91 : : /*
92 : : * Op is not a constant or string, append each argument to the Op
93 : : */
94 [ + + ]: 453388 : while (GET_CURRENT_ARG_TYPE(walk_state->arg_types) &&
95 [ + + ]: 361504 : !walk_state->arg_count) {
96 : 241150 : walk_state->aml = walk_state->parser_state.aml;
97 : :
98 : 241150 : switch (op->common.aml_opcode) {
99 : : case AML_METHOD_OP:
100 : : case AML_BUFFER_OP:
101 : : case AML_PACKAGE_OP:
102 : : case AML_VARIABLE_PACKAGE_OP:
103 : : case AML_WHILE_OP:
104 : :
105 : : break;
106 : :
107 : : default:
108 : :
109 : : ASL_CV_CAPTURE_COMMENTS(walk_state);
110 : : break;
111 : : }
112 : :
113 : 241150 : status =
114 : 241150 : acpi_ps_get_next_arg(walk_state,
115 : : &(walk_state->parser_state),
116 : : GET_CURRENT_ARG_TYPE
117 : : (walk_state->arg_types), &arg);
118 [ - + ]: 241150 : if (ACPI_FAILURE(status)) {
119 : 0 : return_ACPI_STATUS(status);
120 : : }
121 : :
122 [ + + ]: 241150 : if (arg) {
123 : 37089 : acpi_ps_append_arg(op, arg);
124 : : }
125 : :
126 : 241150 : INCREMENT_ARG_LIST(walk_state->arg_types);
127 : : }
128 : :
129 : : ACPI_DEBUG_PRINT((ACPI_DB_PARSE,
130 : : "Final argument count: %8.8X pass %u\n",
131 : : walk_state->arg_count,
132 : 212238 : walk_state->pass_number));
133 : :
134 : : /* Special processing for certain opcodes */
135 : :
136 [ + + + + ]: 212238 : switch (op->common.aml_opcode) {
137 : 988 : case AML_METHOD_OP:
138 : : /*
139 : : * Skip parsing of control method because we don't have enough
140 : : * info in the first pass to parse it correctly.
141 : : *
142 : : * Save the length and address of the body
143 : : */
144 : 988 : op->named.data = walk_state->parser_state.aml;
145 : 988 : op->named.length = (u32)
146 : 988 : (walk_state->parser_state.pkg_end -
147 : 988 : walk_state->parser_state.aml);
148 : :
149 : : /* Skip body of method */
150 : :
151 : 988 : walk_state->parser_state.aml =
152 : 988 : walk_state->parser_state.pkg_end;
153 : 988 : walk_state->arg_count = 0;
154 : 988 : break;
155 : :
156 : 4238 : case AML_BUFFER_OP:
157 : : case AML_PACKAGE_OP:
158 : : case AML_VARIABLE_PACKAGE_OP:
159 : :
160 [ + - ]: 4238 : if ((op->common.parent) &&
161 [ + + ]: 4238 : (op->common.parent->common.aml_opcode ==
162 : : AML_NAME_OP)
163 [ - + ]: 806 : && (walk_state->pass_number <=
164 : : ACPI_IMODE_LOAD_PASS2)) {
165 : : ACPI_DEBUG_PRINT((ACPI_DB_PARSE,
166 : : "Setup Package/Buffer: Pass %u, AML Ptr: %p\n",
167 : : walk_state->pass_number,
168 : 0 : aml_op_start));
169 : :
170 : : /*
171 : : * Skip parsing of Buffers and Packages because we don't have
172 : : * enough info in the first pass to parse them correctly.
173 : : */
174 : 0 : op->named.data = aml_op_start;
175 : 0 : op->named.length = (u32)
176 : 0 : (walk_state->parser_state.pkg_end -
177 : : aml_op_start);
178 : :
179 : : /* Skip body */
180 : :
181 : 0 : walk_state->parser_state.aml =
182 : 0 : walk_state->parser_state.pkg_end;
183 : 0 : walk_state->arg_count = 0;
184 : : }
185 : : break;
186 : :
187 : 6734 : case AML_WHILE_OP:
188 : :
189 [ + + ]: 6734 : if (walk_state->control_state) {
190 : 6682 : walk_state->control_state->control.package_end =
191 : 6682 : walk_state->parser_state.pkg_end;
192 : : }
193 : : break;
194 : :
195 : : default:
196 : :
197 : : /* No action for all other opcodes */
198 : :
199 : : break;
200 : : }
201 : :
202 : : break;
203 : : }
204 : :
205 : : return_ACPI_STATUS(AE_OK);
206 : : }
207 : :
208 : : /*******************************************************************************
209 : : *
210 : : * FUNCTION: acpi_ps_parse_loop
211 : : *
212 : : * PARAMETERS: walk_state - Current state
213 : : *
214 : : * RETURN: Status
215 : : *
216 : : * DESCRIPTION: Parse AML (pointed to by the current parser state) and return
217 : : * a tree of ops.
218 : : *
219 : : ******************************************************************************/
220 : :
221 : 2678 : acpi_status acpi_ps_parse_loop(struct acpi_walk_state *walk_state)
222 : : {
223 : 2678 : acpi_status status = AE_OK;
224 : 2678 : union acpi_parse_object *op = NULL; /* current op */
225 : 2678 : struct acpi_parse_state *parser_state;
226 : 2678 : u8 *aml_op_start = NULL;
227 : 2678 : u8 opcode_length;
228 : :
229 : 2678 : ACPI_FUNCTION_TRACE_PTR(ps_parse_loop, walk_state);
230 : :
231 [ + - ]: 2678 : if (walk_state->descending_callback == NULL) {
232 : : return_ACPI_STATUS(AE_BAD_PARAMETER);
233 : : }
234 : :
235 : 2678 : parser_state = &walk_state->parser_state;
236 : 2678 : walk_state->arg_types = 0;
237 : :
238 : : #ifndef ACPI_CONSTANT_EVAL_ONLY
239 : :
240 [ + + ]: 2678 : if (walk_state->walk_type & ACPI_WALK_METHOD_RESTART) {
241 : :
242 : : /* We are restarting a preempted control method */
243 : :
244 [ + - ]: 364 : if (acpi_ps_has_completed_scope(parser_state)) {
245 : : /*
246 : : * We must check if a predicate to an IF or WHILE statement
247 : : * was just completed
248 : : */
249 [ + - ]: 364 : if ((parser_state->scope->parse_scope.op) &&
250 : 364 : ((parser_state->scope->parse_scope.op->common.
251 : : aml_opcode == AML_IF_OP)
252 [ - + ]: 364 : || (parser_state->scope->parse_scope.op->common.
253 : : aml_opcode == AML_WHILE_OP))
254 [ # # ]: 0 : && (walk_state->control_state)
255 [ # # ]: 0 : && (walk_state->control_state->common.state ==
256 : : ACPI_CONTROL_PREDICATE_EXECUTING)) {
257 : : /*
258 : : * A predicate was just completed, get the value of the
259 : : * predicate and branch based on that value
260 : : */
261 : 0 : walk_state->op = NULL;
262 : 0 : status =
263 : 0 : acpi_ds_get_predicate_value(walk_state,
264 : : ACPI_TO_POINTER
265 : : (TRUE));
266 [ # # ]: 0 : if (ACPI_FAILURE(status)
267 [ # # ]: 0 : && ((status & AE_CODE_MASK) !=
268 : : AE_CODE_CONTROL)) {
269 [ # # ]: 0 : if (status == AE_AML_NO_RETURN_VALUE) {
270 : 0 : ACPI_EXCEPTION((AE_INFO, status,
271 : : "Invoked method did not return a value"));
272 : : }
273 : :
274 : 0 : ACPI_EXCEPTION((AE_INFO, status,
275 : : "GetPredicate Failed"));
276 : 0 : return_ACPI_STATUS(status);
277 : : }
278 : :
279 : 0 : status =
280 : 0 : acpi_ps_next_parse_state(walk_state, op,
281 : : status);
282 : : }
283 : :
284 : 364 : acpi_ps_pop_scope(parser_state, &op,
285 : : &walk_state->arg_types,
286 : : &walk_state->arg_count);
287 : : ACPI_DEBUG_PRINT((ACPI_DB_PARSE,
288 : 364 : "Popped scope, Op=%p\n", op));
289 [ # # ]: 0 : } else if (walk_state->prev_op) {
290 : :
291 : : /* We were in the middle of an op */
292 : :
293 : 0 : op = walk_state->prev_op;
294 : 0 : walk_state->arg_types = walk_state->prev_arg_types;
295 : : }
296 : : }
297 : : #endif
298 : :
299 : : /* Iterative parsing loop, while there is more AML to process: */
300 : :
301 [ + + + + ]: 403559 : while ((parser_state->aml < parser_state->aml_end) || (op)) {
302 : 401297 : ASL_CV_CAPTURE_COMMENTS(walk_state);
303 : :
304 : 401297 : aml_op_start = parser_state->aml;
305 [ + + ]: 401297 : if (!op) {
306 : 232401 : status =
307 : 232401 : acpi_ps_create_op(walk_state, aml_op_start, &op);
308 [ + + ]: 232401 : if (ACPI_FAILURE(status)) {
309 : : /*
310 : : * ACPI_PARSE_MODULE_LEVEL means that we are loading a table by
311 : : * executing it as a control method. However, if we encounter
312 : : * an error while loading the table, we need to keep trying to
313 : : * load the table rather than aborting the table load. Set the
314 : : * status to AE_OK to proceed with the table load.
315 : : */
316 : 78 : if ((walk_state->
317 [ - + ]: 78 : parse_flags & ACPI_PARSE_MODULE_LEVEL)
318 : 0 : && ((status == AE_ALREADY_EXISTS)
319 [ # # ]: 0 : || (status == AE_NOT_FOUND))) {
320 : : status = AE_OK;
321 : : }
322 [ - + ]: 78 : if (status == AE_CTRL_PARSE_CONTINUE) {
323 : 0 : continue;
324 : : }
325 : :
326 [ + + ]: 78 : if (status == AE_CTRL_PARSE_PENDING) {
327 : : status = AE_OK;
328 : : }
329 : :
330 [ - + ]: 52 : if (status == AE_CTRL_TERMINATE) {
331 : : return_ACPI_STATUS(status);
332 : : }
333 : :
334 : 26 : status =
335 : 26 : acpi_ps_complete_op(walk_state, &op,
336 : : status);
337 [ - + ]: 26 : if (ACPI_FAILURE(status)) {
338 : 0 : return_ACPI_STATUS(status);
339 : : }
340 [ - + ]: 26 : if (acpi_ns_opens_scope
341 : 26 : (acpi_ps_get_opcode_info
342 : 26 : (walk_state->opcode)->object_type)) {
343 : : /*
344 : : * If the scope/device op fails to parse, skip the body of
345 : : * the scope op because the parse failure indicates that
346 : : * the device may not exist.
347 : : */
348 : 0 : ACPI_INFO(("Skipping parse of AML opcode: %s (0x%4.4X)", acpi_ps_get_opcode_name(walk_state->opcode), walk_state->opcode));
349 : :
350 : : /*
351 : : * Determine the opcode length before skipping the opcode.
352 : : * An opcode can be 1 byte or 2 bytes in length.
353 : : */
354 : 0 : opcode_length = 1;
355 [ # # ]: 0 : if ((walk_state->opcode & 0xFF00) ==
356 : : AML_EXTENDED_OPCODE) {
357 : 0 : opcode_length = 2;
358 : : }
359 : 0 : walk_state->parser_state.aml =
360 : 0 : walk_state->aml + opcode_length;
361 : :
362 : 0 : walk_state->parser_state.aml =
363 : 0 : acpi_ps_get_next_package_end
364 : : (&walk_state->parser_state);
365 : 0 : walk_state->aml =
366 : : walk_state->parser_state.aml;
367 : : }
368 : :
369 : 26 : continue;
370 : : }
371 : :
372 : 232323 : acpi_ex_start_trace_opcode(op, walk_state);
373 : : }
374 : :
375 : : /*
376 : : * Start arg_count at zero because we don't know if there are
377 : : * any args yet
378 : : */
379 : 401219 : walk_state->arg_count = 0;
380 : :
381 : 401219 : switch (op->common.aml_opcode) {
382 : : case AML_BYTE_OP:
383 : : case AML_WORD_OP:
384 : : case AML_DWORD_OP:
385 : : case AML_QWORD_OP:
386 : :
387 : : break;
388 : :
389 : : default:
390 : :
391 : : ASL_CV_CAPTURE_COMMENTS(walk_state);
392 : : break;
393 : : }
394 : :
395 : : /* Are there any arguments that must be processed? */
396 : :
397 [ + + ]: 401219 : if (walk_state->arg_types) {
398 : :
399 : : /* Get arguments */
400 : :
401 : 249925 : status =
402 : 249925 : acpi_ps_get_arguments(walk_state, aml_op_start, op);
403 [ - + ]: 249925 : if (ACPI_FAILURE(status)) {
404 : 0 : status =
405 : 0 : acpi_ps_complete_op(walk_state, &op,
406 : : status);
407 [ # # ]: 0 : if (ACPI_FAILURE(status)) {
408 : 0 : return_ACPI_STATUS(status);
409 : : }
410 [ # # ]: 0 : if ((walk_state->control_state) &&
411 : 0 : ((walk_state->control_state->control.
412 : : opcode == AML_IF_OP)
413 [ # # ]: 0 : || (walk_state->control_state->control.
414 : : opcode == AML_WHILE_OP))) {
415 : : /*
416 : : * If the if/while op fails to parse, we will skip parsing
417 : : * the body of the op.
418 : : */
419 : 0 : parser_state->aml =
420 : 0 : walk_state->control_state->control.
421 : 0 : aml_predicate_start + 1;
422 : 0 : parser_state->aml =
423 : 0 : acpi_ps_get_next_package_end
424 : : (parser_state);
425 : 0 : walk_state->aml = parser_state->aml;
426 : :
427 : 0 : ACPI_ERROR((AE_INFO,
428 : : "Skipping While/If block"));
429 [ # # ]: 0 : if (*walk_state->aml == AML_ELSE_OP) {
430 : 0 : ACPI_ERROR((AE_INFO,
431 : : "Skipping Else block"));
432 : 0 : walk_state->parser_state.aml =
433 : 0 : walk_state->aml + 1;
434 : 0 : walk_state->parser_state.aml =
435 : 0 : acpi_ps_get_next_package_end
436 : : (parser_state);
437 : 0 : walk_state->aml =
438 : : parser_state->aml;
439 : : }
440 : 0 : ACPI_FREE(acpi_ut_pop_generic_state
441 : : (&walk_state->control_state));
442 : : }
443 : 0 : op = NULL;
444 : 0 : continue;
445 : : }
446 : : }
447 : :
448 : : /* Check for arguments that need to be processed */
449 : :
450 : : ACPI_DEBUG_PRINT((ACPI_DB_PARSE,
451 : : "Parseloop: argument count: %8.8X\n",
452 : 401219 : walk_state->arg_count));
453 : :
454 [ + + ]: 401219 : if (walk_state->arg_count) {
455 : : /*
456 : : * There are arguments (complex ones), push Op and
457 : : * prepare for argument
458 : : */
459 : 180297 : status = acpi_ps_push_scope(parser_state, op,
460 : : walk_state->arg_types,
461 : : walk_state->arg_count);
462 [ - + ]: 180297 : if (ACPI_FAILURE(status)) {
463 : 0 : status =
464 : 0 : acpi_ps_complete_op(walk_state, &op,
465 : : status);
466 [ # # ]: 0 : if (ACPI_FAILURE(status)) {
467 : 0 : return_ACPI_STATUS(status);
468 : : }
469 : :
470 : 0 : continue;
471 : : }
472 : :
473 : 180297 : op = NULL;
474 : 180297 : continue;
475 : : }
476 : :
477 : : /*
478 : : * All arguments have been processed -- Op is complete,
479 : : * prepare for next
480 : : */
481 : 441844 : walk_state->op_info =
482 : 220922 : acpi_ps_get_opcode_info(op->common.aml_opcode);
483 [ + + ]: 220922 : if (walk_state->op_info->flags & AML_NAMED) {
484 [ + + ]: 3770 : if (op->common.aml_opcode == AML_REGION_OP ||
485 : : op->common.aml_opcode == AML_DATA_REGION_OP) {
486 : : /*
487 : : * Skip parsing of control method or opregion body,
488 : : * because we don't have enough info in the first pass
489 : : * to parse them correctly.
490 : : *
491 : : * Completed parsing an op_region declaration, we now
492 : : * know the length.
493 : : */
494 : 104 : op->named.length =
495 : 104 : (u32) (parser_state->aml - op->named.data);
496 : : }
497 : : }
498 : :
499 [ + + ]: 220922 : if (walk_state->op_info->flags & AML_CREATE) {
500 : : /*
501 : : * Backup to beginning of create_XXXfield declaration (1 for
502 : : * Opcode)
503 : : *
504 : : * body_length is unknown until we parse the body
505 : : */
506 : 130 : op->named.length =
507 : 130 : (u32) (parser_state->aml - op->named.data);
508 : : }
509 : :
510 [ - + ]: 220922 : if (op->common.aml_opcode == AML_BANK_FIELD_OP) {
511 : : /*
512 : : * Backup to beginning of bank_field declaration
513 : : *
514 : : * body_length is unknown until we parse the body
515 : : */
516 : 0 : op->named.length =
517 : 0 : (u32) (parser_state->aml - op->named.data);
518 : : }
519 : :
520 : : /* This op complete, notify the dispatcher */
521 : :
522 [ + + ]: 220922 : if (walk_state->ascending_callback != NULL) {
523 : 213811 : walk_state->op = op;
524 : 213811 : walk_state->opcode = op->common.aml_opcode;
525 : :
526 : 213811 : status = walk_state->ascending_callback(walk_state);
527 : 213811 : status =
528 : 213811 : acpi_ps_next_parse_state(walk_state, op, status);
529 [ + + ]: 213811 : if (status == AE_CTRL_PENDING) {
530 : : status = AE_OK;
531 : : } else
532 : 210483 : if ((walk_state->
533 [ + + ]: 210483 : parse_flags & ACPI_PARSE_MODULE_LEVEL)
534 [ + - ]: 6227 : && (ACPI_AML_EXCEPTION(status)
535 : 6227 : || status == AE_ALREADY_EXISTS
536 [ - + ]: 6227 : || status == AE_NOT_FOUND)) {
537 : : /*
538 : : * ACPI_PARSE_MODULE_LEVEL flag means that we
539 : : * are currently loading a table by executing
540 : : * it as a control method. However, if we
541 : : * encounter an error while loading the table,
542 : : * we need to keep trying to load the table
543 : : * rather than aborting the table load (setting
544 : : * the status to AE_OK continues the table
545 : : * load). If we get a failure at this point, it
546 : : * means that the dispatcher got an error while
547 : : * trying to execute the Op.
548 : : */
549 : 0 : status = AE_OK;
550 : : }
551 : : }
552 : :
553 : 220922 : status = acpi_ps_complete_op(walk_state, &op, status);
554 [ + + ]: 220922 : if (ACPI_FAILURE(status)) {
555 : 364 : return_ACPI_STATUS(status);
556 : : }
557 : :
558 : : } /* while parser_state->Aml */
559 : :
560 : 2262 : status = acpi_ps_complete_final_op(walk_state, op, status);
561 : 2262 : return_ACPI_STATUS(status);
562 : : }
|