projects/linux·blob master · refs

701 lines · 17.8 KiB

1// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
2/******************************************************************************
3 *
4 * Module Name: psparse - Parser top level AML parse routines
5 *
6 * Copyright (C) 2000 - 2026, Intel Corp.
7 *
8 *****************************************************************************/
9
10/*
11 * Parse the AML and build an operation tree as most interpreters,
12 * like Perl, do. Parsing is done by hand rather than with a YACC
13 * generated parser to tightly constrain stack and dynamic memory
14 * usage. At the same time, parsing is kept flexible and the code
15 * fairly compact by parsing based on a list of AML opcode
16 * templates in aml_op_info[]
17 */
18
19#include <acpi/acpi.h>
20#include "accommon.h"
21#include "acparser.h"
22#include "acdispat.h"
23#include "amlcode.h"
24#include "acinterp.h"
25#include "acnamesp.h"
26
27#define _COMPONENT ACPI_PARSER
28ACPI_MODULE_NAME("psparse")
29
30/*******************************************************************************
31 *
32 * FUNCTION: acpi_ps_get_opcode_size
33 *
34 * PARAMETERS: opcode - An AML opcode
35 *
36 * RETURN: Size of the opcode, in bytes (1 or 2)
37 *
38 * DESCRIPTION: Get the size of the current opcode.
39 *
40 ******************************************************************************/
41u32 acpi_ps_get_opcode_size(u32 opcode)
42{
43
44 /* Extended (2-byte) opcode if > 255 */
45
46 if (opcode > 0x00FF) {
47 return (2);
48 }
49
50 /* Otherwise, just a single byte opcode */
51
52 return (1);
53}
54
55/*******************************************************************************
56 *
57 * FUNCTION: acpi_ps_peek_opcode
58 *
59 * PARAMETERS: parser_state - A parser state object
60 *
61 * RETURN: Next AML opcode
62 *
63 * DESCRIPTION: Get next AML opcode (without incrementing AML pointer)
64 *
65 ******************************************************************************/
66
67u16 acpi_ps_peek_opcode(struct acpi_parse_state * parser_state)
68{
69 u8 *aml;
70 u16 opcode;
71
72 aml = parser_state->aml;
73 if (aml >= parser_state->aml_end) {
74 return (0xFFFF);
75 }
76 opcode = (u16) ACPI_GET8(aml);
77
78 if (opcode == AML_EXTENDED_PREFIX) {
79
80 /* Extended opcode, get the second opcode byte */
81
82 aml++;
83 if (aml >= parser_state->aml_end) {
84 return (0xFFFF);
85 }
86 opcode = (u16) ((opcode << 8) | ACPI_GET8(aml));
87 }
88
89 return (opcode);
90}
91
92/*******************************************************************************
93 *
94 * FUNCTION: acpi_ps_complete_this_op
95 *
96 * PARAMETERS: walk_state - Current State
97 * op - Op to complete
98 *
99 * RETURN: Status
100 *
101 * DESCRIPTION: Perform any cleanup at the completion of an Op.
102 *
103 ******************************************************************************/
104
105acpi_status
106acpi_ps_complete_this_op(struct acpi_walk_state *walk_state,
107 union acpi_parse_object *op)
108{
109 union acpi_parse_object *prev;
110 union acpi_parse_object *next;
111 const struct acpi_opcode_info *parent_info;
112 union acpi_parse_object *replacement_op = NULL;
113 acpi_status status = AE_OK;
114
115 ACPI_FUNCTION_TRACE_PTR(ps_complete_this_op, op);
116
117 /* Check for null Op, can happen if AML code is corrupt */
118
119 if (!op) {
120 return_ACPI_STATUS(AE_OK); /* OK for now */
121 }
122
123 acpi_ex_stop_trace_opcode(op, walk_state);
124
125 /* Delete this op and the subtree below it if asked to */
126
127 if (((walk_state->parse_flags & ACPI_PARSE_TREE_MASK) !=
128 ACPI_PARSE_DELETE_TREE)
129 || (walk_state->op_info->class == AML_CLASS_ARGUMENT)) {
130 return_ACPI_STATUS(AE_OK);
131 }
132
133 /* Make sure that we only delete this subtree */
134
135 if (op->common.parent) {
136 prev = op->common.parent->common.value.arg;
137 if (!prev) {
138
139 /* Nothing more to do */
140
141 goto cleanup;
142 }
143
144 /*
145 * Check if we need to replace the operator and its subtree
146 * with a return value op (placeholder op)
147 */
148 parent_info =
149 acpi_ps_get_opcode_info(op->common.parent->common.
150 aml_opcode);
151
152 switch (parent_info->class) {
153 case AML_CLASS_CONTROL:
154
155 break;
156
157 case AML_CLASS_CREATE:
158 /*
159 * These opcodes contain term_arg operands. The current
160 * op must be replaced by a placeholder return op
161 */
162 replacement_op =
163 acpi_ps_alloc_op(AML_INT_RETURN_VALUE_OP,
164 op->common.aml);
165 if (!replacement_op) {
166 status = AE_NO_MEMORY;
167 }
168 break;
169
170 case AML_CLASS_NAMED_OBJECT:
171 /*
172 * These opcodes contain term_arg operands. The current
173 * op must be replaced by a placeholder return op
174 */
175 if ((op->common.parent->common.aml_opcode ==
176 AML_REGION_OP)
177 || (op->common.parent->common.aml_opcode ==
178 AML_DATA_REGION_OP)
179 || (op->common.parent->common.aml_opcode ==
180 AML_BUFFER_OP)
181 || (op->common.parent->common.aml_opcode ==
182 AML_PACKAGE_OP)
183 || (op->common.parent->common.aml_opcode ==
184 AML_BANK_FIELD_OP)
185 || (op->common.parent->common.aml_opcode ==
186 AML_VARIABLE_PACKAGE_OP)) {
187 replacement_op =
188 acpi_ps_alloc_op(AML_INT_RETURN_VALUE_OP,
189 op->common.aml);
190 if (!replacement_op) {
191 status = AE_NO_MEMORY;
192 }
193 } else
194 if ((op->common.parent->common.aml_opcode ==
195 AML_NAME_OP)
196 && (walk_state->pass_number <=
197 ACPI_IMODE_LOAD_PASS2)) {
198 if ((op->common.aml_opcode == AML_BUFFER_OP)
199 || (op->common.aml_opcode == AML_PACKAGE_OP)
200 || (op->common.aml_opcode ==
201 AML_VARIABLE_PACKAGE_OP)) {
202 replacement_op =
203 acpi_ps_alloc_op(op->common.
204 aml_opcode,
205 op->common.aml);
206 if (!replacement_op) {
207 status = AE_NO_MEMORY;
208 } else {
209 replacement_op->named.data =
210 op->named.data;
211 replacement_op->named.length =
212 op->named.length;
213 }
214 }
215 }
216 break;
217
218 default:
219
220 replacement_op =
221 acpi_ps_alloc_op(AML_INT_RETURN_VALUE_OP,
222 op->common.aml);
223 if (!replacement_op) {
224 status = AE_NO_MEMORY;
225 }
226 }
227
228 /* We must unlink this op from the parent tree */
229
230 if (prev == op) {
231
232 /* This op is the first in the list */
233
234 if (replacement_op) {
235 replacement_op->common.parent =
236 op->common.parent;
237 replacement_op->common.value.arg = NULL;
238 replacement_op->common.node = op->common.node;
239 op->common.parent->common.value.arg =
240 replacement_op;
241 replacement_op->common.next = op->common.next;
242 } else {
243 op->common.parent->common.value.arg =
244 op->common.next;
245 }
246 }
247
248 /* Search the parent list */
249
250 else
251 while (prev) {
252
253 /* Traverse all siblings in the parent's argument list */
254
255 next = prev->common.next;
256 if (next == op) {
257 if (replacement_op) {
258 replacement_op->common.parent =
259 op->common.parent;
260 replacement_op->common.value.
261 arg = NULL;
262 replacement_op->common.node =
263 op->common.node;
264 prev->common.next =
265 replacement_op;
266 replacement_op->common.next =
267 op->common.next;
268 next = NULL;
269 } else {
270 prev->common.next =
271 op->common.next;
272 next = NULL;
273 }
274 }
275 prev = next;
276 }
277 }
278
279cleanup:
280
281 /* Now we can actually delete the subtree rooted at Op */
282
283 acpi_ps_delete_parse_tree(op);
284 return_ACPI_STATUS(status);
285}
286
287/*******************************************************************************
288 *
289 * FUNCTION: acpi_ps_next_parse_state
290 *
291 * PARAMETERS: walk_state - Current state
292 * op - Current parse op
293 * callback_status - Status from previous operation
294 *
295 * RETURN: Status
296 *
297 * DESCRIPTION: Update the parser state based upon the return exception from
298 * the parser callback.
299 *
300 ******************************************************************************/
301
302acpi_status
303acpi_ps_next_parse_state(struct acpi_walk_state *walk_state,
304 union acpi_parse_object *op,
305 acpi_status callback_status)
306{
307 struct acpi_parse_state *parser_state = &walk_state->parser_state;
308 acpi_status status = AE_CTRL_PENDING;
309 u8 *aml;
310
311 ACPI_FUNCTION_TRACE_PTR(ps_next_parse_state, op);
312
313 switch (callback_status) {
314 case AE_CTRL_TERMINATE:
315 /*
316 * A control method was terminated via a RETURN statement.
317 * The walk of this method is complete.
318 */
319 parser_state->aml = parser_state->aml_end;
320 status = AE_CTRL_TERMINATE;
321 break;
322
323 case AE_CTRL_BREAK:
324
325 parser_state->aml = walk_state->aml_last_while;
326 walk_state->control_state->common.value = FALSE;
327 status = AE_CTRL_BREAK;
328 break;
329
330 case AE_CTRL_CONTINUE:
331
332 parser_state->aml = walk_state->aml_last_while;
333 status = AE_CTRL_CONTINUE;
334 break;
335
336 case AE_CTRL_PENDING:
337
338 parser_state->aml = walk_state->aml_last_while;
339 break;
340
341#if 0
342 case AE_CTRL_SKIP:
343
344 parser_state->aml = parser_state->scope->parse_scope.pkg_end;
345 status = AE_OK;
346 break;
347#endif
348
349 case AE_CTRL_TRUE:
350 /*
351 * Predicate of an IF was true, and we are at the matching ELSE.
352 * Just close out this package
353 */
354 aml = parser_state->aml;
355
356 parser_state->aml = acpi_ps_get_next_package_end(parser_state);
357 if ((parser_state->aml > parser_state->aml_end) ||
358 (parser_state->aml < aml)) {
359 status = AE_AML_PACKAGE_LIMIT;
360 break;
361 }
362 status = AE_CTRL_PENDING;
363 break;
364
365 case AE_CTRL_FALSE:
366 /*
367 * Either an IF/WHILE Predicate was false or we encountered a BREAK
368 * opcode. In both cases, we do not execute the rest of the
369 * package; We simply close out the parent (finishing the walk of
370 * this branch of the tree) and continue execution at the parent
371 * level.
372 */
373 parser_state->aml = parser_state->scope->parse_scope.pkg_end;
374
375 /* In the case of a BREAK, just force a predicate (if any) to FALSE */
376
377 walk_state->control_state->common.value = FALSE;
378 status = AE_CTRL_END;
379 break;
380
381 case AE_CTRL_TRANSFER:
382
383 /* A method call (invocation) -- transfer control */
384
385 status = AE_CTRL_TRANSFER;
386 walk_state->prev_op = op;
387 walk_state->method_call_op = op;
388 walk_state->method_call_node =
389 (op->common.value.arg)->common.node;
390
391 /* Will return value (if any) be used by the caller? */
392
393 walk_state->return_used =
394 acpi_ds_is_result_used(op, walk_state);
395 break;
396
397 default:
398
399 status = callback_status;
400 if (ACPI_CNTL_EXCEPTION(callback_status)) {
401 status = AE_OK;
402 }
403 break;
404 }
405
406 return_ACPI_STATUS(status);
407}
408
409/*******************************************************************************
410 *
411 * FUNCTION: acpi_ps_parse_aml
412 *
413 * PARAMETERS: walk_state - Current state
414 *
415 *
416 * RETURN: Status
417 *
418 * DESCRIPTION: Parse raw AML and return a tree of ops
419 *
420 ******************************************************************************/
421
422acpi_status acpi_ps_parse_aml(struct acpi_walk_state *walk_state)
423{
424 acpi_status status;
425 struct acpi_thread_state *thread;
426 struct acpi_thread_state *prev_walk_list = acpi_gbl_current_walk_list;
427 struct acpi_walk_state *previous_walk_state;
428
429 ACPI_FUNCTION_TRACE(ps_parse_aml);
430
431 ACPI_DEBUG_PRINT((ACPI_DB_PARSE,
432 "Entered with WalkState=%p Aml=%p size=%X\n",
433 walk_state, walk_state->parser_state.aml,
434 walk_state->parser_state.aml_size));
435
436 if (!walk_state->parser_state.aml) {
437 return_ACPI_STATUS(AE_BAD_ADDRESS);
438 }
439
440 /* Create and initialize a new thread state */
441
442 thread = acpi_ut_create_thread_state();
443 if (!thread) {
444 if (walk_state->method_desc) {
445
446 /* Executing a control method - additional cleanup */
447
448 acpi_ds_terminate_control_method(walk_state->
449 method_desc,
450 walk_state);
451 }
452
453 acpi_ds_delete_walk_state(walk_state);
454 return_ACPI_STATUS(AE_NO_MEMORY);
455 }
456
457 walk_state->thread = thread;
458
459 /*
460 * If executing a method, the starting sync_level is this method's
461 * sync_level
462 */
463 if (walk_state->method_desc) {
464 walk_state->thread->current_sync_level =
465 walk_state->method_desc->method.sync_level;
466 }
467
468 acpi_ds_push_walk_state(walk_state, thread);
469
470 /*
471 * This global allows the AML debugger to get a handle to the currently
472 * executing control method.
473 */
474 acpi_gbl_current_walk_list = thread;
475
476 /*
477 * Execute the walk loop as long as there is a valid Walk State. This
478 * handles nested control method invocations without recursion.
479 */
480 ACPI_DEBUG_PRINT((ACPI_DB_PARSE, "State=%p\n", walk_state));
481
482 status = AE_OK;
483 while (walk_state) {
484 if (ACPI_SUCCESS(status)) {
485 /*
486 * The parse_loop executes AML until the method terminates
487 * or calls another method.
488 */
489 status = acpi_ps_parse_loop(walk_state);
490 }
491
492 ACPI_DEBUG_PRINT((ACPI_DB_PARSE,
493 "Completed one call to walk loop, %s State=%p\n",
494 acpi_format_exception(status), walk_state));
495
496 if (walk_state->method_pathname && walk_state->method_is_nested) {
497
498 /* Optional object evaluation log */
499
500 ACPI_DEBUG_PRINT_RAW((ACPI_DB_EVALUATION,
501 "%-26s: %*s%s\n",
502 " Exit nested method",
503 (walk_state->
504 method_nesting_depth + 1) * 3,
505 " ",
506 &walk_state->method_pathname[1]));
507
508 ACPI_FREE(walk_state->method_pathname);
509 walk_state->method_is_nested = FALSE;
510 }
511 if (status == AE_CTRL_TRANSFER) {
512 /*
513 * A method call was detected.
514 * Transfer control to the called control method
515 */
516 status =
517 acpi_ds_call_control_method(thread, walk_state,
518 NULL);
519 if (ACPI_FAILURE(status)) {
520 status =
521 acpi_ds_method_error(status, walk_state);
522 }
523
524 /*
525 * If the transfer to the new method method call worked,
526 * a new walk state was created -- get it
527 */
528 walk_state = acpi_ds_get_current_walk_state(thread);
529 continue;
530 } else if (status == AE_CTRL_TERMINATE) {
531 status = AE_OK;
532 } else if ((status != AE_OK) && (walk_state->method_desc)) {
533
534 /* Either the method parse or actual execution failed */
535
536 acpi_ex_exit_interpreter();
537 if (status == AE_ABORT_METHOD) {
538 acpi_ns_print_node_pathname(walk_state->
539 method_node,
540 "Aborting method");
541 acpi_os_printf("\n");
542 } else {
543 ACPI_ERROR_METHOD("Aborting method",
544 walk_state->method_node, NULL,
545 status);
546 }
547 acpi_ex_enter_interpreter();
548
549 /* Check for possible multi-thread reentrancy problem */
550
551 if ((status == AE_ALREADY_EXISTS) &&
552 (!(walk_state->method_desc->method.info_flags &
553 ACPI_METHOD_SERIALIZED))) {
554 /*
555 * Method is not serialized and tried to create an object
556 * twice. The probable cause is that the method cannot
557 * handle reentrancy. Mark as "pending serialized" now, and
558 * then mark "serialized" when the last thread exits.
559 */
560 walk_state->method_desc->method.info_flags |=
561 ACPI_METHOD_SERIALIZED_PENDING;
562 }
563 }
564
565 /* We are done with this walk, move on to the parent if any */
566
567 walk_state = acpi_ds_pop_walk_state(thread);
568
569 /* Reset the current scope to the beginning of scope stack */
570
571 acpi_ds_scope_stack_clear(walk_state);
572
573 /*
574 * If we just returned from the execution of a control method or if we
575 * encountered an error during the method parse phase, there's lots of
576 * cleanup to do
577 */
578 if (((walk_state->parse_flags & ACPI_PARSE_MODE_MASK) ==
579 ACPI_PARSE_EXECUTE &&
580 !(walk_state->parse_flags & ACPI_PARSE_MODULE_LEVEL)) ||
581 (ACPI_FAILURE(status))) {
582 acpi_ds_terminate_control_method(walk_state->
583 method_desc,
584 walk_state);
585 }
586
587 /* Delete this walk state and all linked control states */
588
589 acpi_ps_cleanup_scope(&walk_state->parser_state);
590 previous_walk_state = walk_state;
591
592 ACPI_DEBUG_PRINT((ACPI_DB_PARSE,
593 "ReturnValue=%p, ImplicitValue=%p State=%p\n",
594 walk_state->return_desc,
595 walk_state->implicit_return_obj, walk_state));
596
597 /* Check if we have restarted a preempted walk */
598
599 walk_state = acpi_ds_get_current_walk_state(thread);
600 if (walk_state) {
601 if (ACPI_SUCCESS(status)) {
602 /*
603 * There is another walk state, restart it.
604 * If the method return value is not used by the parent,
605 * The object is deleted
606 */
607 if (!previous_walk_state->return_desc) {
608 /*
609 * In slack mode execution, if there is no return value
610 * we should implicitly return zero (0) as a default value.
611 */
612 if (acpi_gbl_enable_interpreter_slack &&
613 !previous_walk_state->
614 implicit_return_obj) {
615 previous_walk_state->
616 implicit_return_obj =
617 acpi_ut_create_integer_object
618 ((u64) 0);
619 if (!previous_walk_state->
620 implicit_return_obj) {
621 return_ACPI_STATUS
622 (AE_NO_MEMORY);
623 }
624 }
625
626 /* Restart the calling control method */
627
628 status =
629 acpi_ds_restart_control_method
630 (walk_state,
631 previous_walk_state->
632 implicit_return_obj);
633 } else {
634 /*
635 * We have a valid return value, delete any implicit
636 * return value.
637 */
638 acpi_ds_clear_implicit_return
639 (previous_walk_state);
640
641 status =
642 acpi_ds_restart_control_method
643 (walk_state,
644 previous_walk_state->return_desc);
645 }
646 if (ACPI_SUCCESS(status)) {
647 walk_state->walk_type |=
648 ACPI_WALK_METHOD_RESTART;
649 }
650 } else {
651 /* On error, delete any return object or implicit return */
652
653 acpi_ut_remove_reference(previous_walk_state->
654 return_desc);
655 acpi_ds_clear_implicit_return
656 (previous_walk_state);
657 }
658 }
659
660 /*
661 * Just completed a 1st-level method, save the final internal return
662 * value (if any)
663 */
664 else if (previous_walk_state->caller_return_desc) {
665 if (previous_walk_state->implicit_return_obj) {
666 *(previous_walk_state->caller_return_desc) =
667 previous_walk_state->implicit_return_obj;
668 } else {
669 /* NULL if no return value */
670
671 *(previous_walk_state->caller_return_desc) =
672 previous_walk_state->return_desc;
673 }
674 } else {
675 if (previous_walk_state->return_desc) {
676
677 /* Caller doesn't want it, must delete it */
678
679 acpi_ut_remove_reference(previous_walk_state->
680 return_desc);
681 }
682 if (previous_walk_state->implicit_return_obj) {
683
684 /* Caller doesn't want it, must delete it */
685
686 acpi_ut_remove_reference(previous_walk_state->
687 implicit_return_obj);
688 }
689 }
690
691 acpi_ds_delete_walk_state(previous_walk_state);
692 }
693
694 /* Normal exit */
695
696 acpi_ex_release_all_mutexes(thread);
697 acpi_ut_delete_generic_state(ACPI_CAST_PTR
698 (union acpi_generic_state, thread));
699 acpi_gbl_current_walk_list = prev_walk_list;
700 return_ACPI_STATUS(status);
701}