1 | // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 |
2 | /****************************************************************************** |
3 | * |
4 | * Module Name: psobject - Support for parse objects |
5 | * |
6 | * Copyright (C) 2000 - 2023, Intel Corp. |
7 | * |
8 | *****************************************************************************/ |
9 | |
10 | #include <acpi/acpi.h> |
11 | #include "accommon.h" |
12 | #include "acparser.h" |
13 | #include "amlcode.h" |
14 | #include "acconvert.h" |
15 | #include "acnamesp.h" |
16 | |
17 | #define _COMPONENT ACPI_PARSER |
18 | ACPI_MODULE_NAME("psobject" ) |
19 | |
20 | /* Local prototypes */ |
21 | static acpi_status acpi_ps_get_aml_opcode(struct acpi_walk_state *walk_state); |
22 | |
23 | /******************************************************************************* |
24 | * |
25 | * FUNCTION: acpi_ps_get_aml_opcode |
26 | * |
27 | * PARAMETERS: walk_state - Current state |
28 | * |
29 | * RETURN: Status |
30 | * |
31 | * DESCRIPTION: Extract the next AML opcode from the input stream. |
32 | * |
33 | ******************************************************************************/ |
34 | |
35 | static acpi_status acpi_ps_get_aml_opcode(struct acpi_walk_state *walk_state) |
36 | { |
37 | ACPI_ERROR_ONLY(u32 aml_offset); |
38 | |
39 | ACPI_FUNCTION_TRACE_PTR(ps_get_aml_opcode, walk_state); |
40 | |
41 | walk_state->aml = walk_state->parser_state.aml; |
42 | walk_state->opcode = acpi_ps_peek_opcode(state: &(walk_state->parser_state)); |
43 | |
44 | /* |
45 | * First cut to determine what we have found: |
46 | * 1) A valid AML opcode |
47 | * 2) A name string |
48 | * 3) An unknown/invalid opcode |
49 | */ |
50 | walk_state->op_info = acpi_ps_get_opcode_info(opcode: walk_state->opcode); |
51 | |
52 | switch (walk_state->op_info->class) { |
53 | case AML_CLASS_ASCII: |
54 | case AML_CLASS_PREFIX: |
55 | /* |
56 | * Starts with a valid prefix or ASCII char, this is a name |
57 | * string. Convert the bare name string to a namepath. |
58 | */ |
59 | walk_state->opcode = AML_INT_NAMEPATH_OP; |
60 | walk_state->arg_types = ARGP_NAMESTRING; |
61 | break; |
62 | |
63 | case AML_CLASS_UNKNOWN: |
64 | |
65 | /* The opcode is unrecognized. Complain and skip unknown opcodes */ |
66 | |
67 | if (walk_state->pass_number == 2) { |
68 | ACPI_ERROR_ONLY(aml_offset = |
69 | (u32)ACPI_PTR_DIFF(walk_state->aml, |
70 | walk_state-> |
71 | parser_state. |
72 | aml_start)); |
73 | |
74 | ACPI_ERROR((AE_INFO, |
75 | "Unknown opcode 0x%.2X at table offset 0x%.4X, ignoring" , |
76 | walk_state->opcode, |
77 | (u32)(aml_offset + |
78 | sizeof(struct acpi_table_header)))); |
79 | |
80 | ACPI_DUMP_BUFFER((walk_state->parser_state.aml - 16), |
81 | 48); |
82 | |
83 | #ifdef ACPI_ASL_COMPILER |
84 | /* |
85 | * This is executed for the disassembler only. Output goes |
86 | * to the disassembled ASL output file. |
87 | */ |
88 | acpi_os_printf |
89 | ("/*\nError: Unknown opcode 0x%.2X at table offset 0x%.4X, context:\n" , |
90 | walk_state->opcode, |
91 | (u32)(aml_offset + |
92 | sizeof(struct acpi_table_header))); |
93 | |
94 | ACPI_ERROR((AE_INFO, |
95 | "Aborting disassembly, AML byte code is corrupt" )); |
96 | |
97 | /* Dump the context surrounding the invalid opcode */ |
98 | |
99 | acpi_ut_dump_buffer(((u8 *)walk_state->parser_state. |
100 | aml - 16), 48, DB_BYTE_DISPLAY, |
101 | (aml_offset + |
102 | sizeof(struct acpi_table_header) - |
103 | 16)); |
104 | acpi_os_printf(" */\n" ); |
105 | |
106 | /* |
107 | * Just abort the disassembly, cannot continue because the |
108 | * parser is essentially lost. The disassembler can then |
109 | * randomly fail because an ill-constructed parse tree |
110 | * can result. |
111 | */ |
112 | return_ACPI_STATUS(AE_AML_BAD_OPCODE); |
113 | #endif |
114 | } |
115 | |
116 | /* Increment past one-byte or two-byte opcode */ |
117 | |
118 | walk_state->parser_state.aml++; |
119 | if (walk_state->opcode > 0xFF) { /* Can only happen if first byte is 0x5B */ |
120 | walk_state->parser_state.aml++; |
121 | } |
122 | |
123 | return_ACPI_STATUS(AE_CTRL_PARSE_CONTINUE); |
124 | |
125 | default: |
126 | |
127 | /* Found opcode info, this is a normal opcode */ |
128 | |
129 | walk_state->parser_state.aml += |
130 | acpi_ps_get_opcode_size(opcode: walk_state->opcode); |
131 | walk_state->arg_types = walk_state->op_info->parse_args; |
132 | break; |
133 | } |
134 | |
135 | return_ACPI_STATUS(AE_OK); |
136 | } |
137 | |
138 | /******************************************************************************* |
139 | * |
140 | * FUNCTION: acpi_ps_build_named_op |
141 | * |
142 | * PARAMETERS: walk_state - Current state |
143 | * aml_op_start - Begin of named Op in AML |
144 | * unnamed_op - Early Op (not a named Op) |
145 | * op - Returned Op |
146 | * |
147 | * RETURN: Status |
148 | * |
149 | * DESCRIPTION: Parse a named Op |
150 | * |
151 | ******************************************************************************/ |
152 | |
153 | acpi_status |
154 | acpi_ps_build_named_op(struct acpi_walk_state *walk_state, |
155 | u8 *aml_op_start, |
156 | union acpi_parse_object *unnamed_op, |
157 | union acpi_parse_object **op) |
158 | { |
159 | acpi_status status = AE_OK; |
160 | union acpi_parse_object *arg = NULL; |
161 | |
162 | ACPI_FUNCTION_TRACE_PTR(ps_build_named_op, walk_state); |
163 | |
164 | unnamed_op->common.value.arg = NULL; |
165 | unnamed_op->common.arg_list_length = 0; |
166 | unnamed_op->common.aml_opcode = walk_state->opcode; |
167 | |
168 | /* |
169 | * Get and append arguments until we find the node that contains |
170 | * the name (the type ARGP_NAME). |
171 | */ |
172 | while (GET_CURRENT_ARG_TYPE(walk_state->arg_types) && |
173 | (GET_CURRENT_ARG_TYPE(walk_state->arg_types) != ARGP_NAME)) { |
174 | ASL_CV_CAPTURE_COMMENTS(walk_state); |
175 | status = |
176 | acpi_ps_get_next_arg(walk_state, |
177 | parser_state: &(walk_state->parser_state), |
178 | GET_CURRENT_ARG_TYPE(walk_state-> |
179 | arg_types), return_arg: &arg); |
180 | if (ACPI_FAILURE(status)) { |
181 | return_ACPI_STATUS(status); |
182 | } |
183 | |
184 | acpi_ps_append_arg(op: unnamed_op, arg); |
185 | INCREMENT_ARG_LIST(walk_state->arg_types); |
186 | } |
187 | |
188 | /* are there any inline comments associated with the name_seg?? If so, save this. */ |
189 | |
190 | ASL_CV_CAPTURE_COMMENTS(walk_state); |
191 | |
192 | #ifdef ACPI_ASL_COMPILER |
193 | if (acpi_gbl_current_inline_comment != NULL) { |
194 | unnamed_op->common.name_comment = |
195 | acpi_gbl_current_inline_comment; |
196 | acpi_gbl_current_inline_comment = NULL; |
197 | } |
198 | #endif |
199 | |
200 | /* |
201 | * Make sure that we found a NAME and didn't run out of arguments |
202 | */ |
203 | if (!GET_CURRENT_ARG_TYPE(walk_state->arg_types)) { |
204 | return_ACPI_STATUS(AE_AML_NO_OPERAND); |
205 | } |
206 | |
207 | /* We know that this arg is a name, move to next arg */ |
208 | |
209 | INCREMENT_ARG_LIST(walk_state->arg_types); |
210 | |
211 | /* |
212 | * Find the object. This will either insert the object into |
213 | * the namespace or simply look it up |
214 | */ |
215 | walk_state->op = NULL; |
216 | |
217 | status = walk_state->descending_callback(walk_state, op); |
218 | if (ACPI_FAILURE(status)) { |
219 | if (status != AE_CTRL_TERMINATE) { |
220 | ACPI_EXCEPTION((AE_INFO, status, |
221 | "During name lookup/catalog" )); |
222 | } |
223 | return_ACPI_STATUS(status); |
224 | } |
225 | |
226 | if (!*op) { |
227 | return_ACPI_STATUS(AE_CTRL_PARSE_CONTINUE); |
228 | } |
229 | |
230 | status = acpi_ps_next_parse_state(walk_state, op: *op, callback_status: status); |
231 | if (ACPI_FAILURE(status)) { |
232 | if (status == AE_CTRL_PENDING) { |
233 | status = AE_CTRL_PARSE_PENDING; |
234 | } |
235 | return_ACPI_STATUS(status); |
236 | } |
237 | |
238 | acpi_ps_append_arg(op: *op, arg: unnamed_op->common.value.arg); |
239 | |
240 | #ifdef ACPI_ASL_COMPILER |
241 | |
242 | /* save any comments that might be associated with unnamed_op. */ |
243 | |
244 | (*op)->common.inline_comment = unnamed_op->common.inline_comment; |
245 | (*op)->common.end_node_comment = unnamed_op->common.end_node_comment; |
246 | (*op)->common.close_brace_comment = |
247 | unnamed_op->common.close_brace_comment; |
248 | (*op)->common.name_comment = unnamed_op->common.name_comment; |
249 | (*op)->common.comment_list = unnamed_op->common.comment_list; |
250 | (*op)->common.end_blk_comment = unnamed_op->common.end_blk_comment; |
251 | (*op)->common.cv_filename = unnamed_op->common.cv_filename; |
252 | (*op)->common.cv_parent_filename = |
253 | unnamed_op->common.cv_parent_filename; |
254 | (*op)->named.aml = unnamed_op->common.aml; |
255 | |
256 | unnamed_op->common.inline_comment = NULL; |
257 | unnamed_op->common.end_node_comment = NULL; |
258 | unnamed_op->common.close_brace_comment = NULL; |
259 | unnamed_op->common.name_comment = NULL; |
260 | unnamed_op->common.comment_list = NULL; |
261 | unnamed_op->common.end_blk_comment = NULL; |
262 | #endif |
263 | |
264 | if ((*op)->common.aml_opcode == AML_REGION_OP || |
265 | (*op)->common.aml_opcode == AML_DATA_REGION_OP) { |
266 | /* |
267 | * Defer final parsing of an operation_region body, because we don't |
268 | * have enough info in the first pass to parse it correctly (i.e., |
269 | * there may be method calls within the term_arg elements of the body.) |
270 | * |
271 | * However, we must continue parsing because the opregion is not a |
272 | * standalone package -- we don't know where the end is at this point. |
273 | * |
274 | * (Length is unknown until parse of the body complete) |
275 | */ |
276 | (*op)->named.data = aml_op_start; |
277 | (*op)->named.length = 0; |
278 | } |
279 | |
280 | return_ACPI_STATUS(AE_OK); |
281 | } |
282 | |
283 | /******************************************************************************* |
284 | * |
285 | * FUNCTION: acpi_ps_create_op |
286 | * |
287 | * PARAMETERS: walk_state - Current state |
288 | * aml_op_start - Op start in AML |
289 | * new_op - Returned Op |
290 | * |
291 | * RETURN: Status |
292 | * |
293 | * DESCRIPTION: Get Op from AML |
294 | * |
295 | ******************************************************************************/ |
296 | |
297 | acpi_status |
298 | acpi_ps_create_op(struct acpi_walk_state *walk_state, |
299 | u8 *aml_op_start, union acpi_parse_object **new_op) |
300 | { |
301 | acpi_status status = AE_OK; |
302 | union acpi_parse_object *op; |
303 | union acpi_parse_object *named_op = NULL; |
304 | union acpi_parse_object *parent_scope; |
305 | u8 argument_count; |
306 | const struct acpi_opcode_info *op_info; |
307 | |
308 | ACPI_FUNCTION_TRACE_PTR(ps_create_op, walk_state); |
309 | |
310 | status = acpi_ps_get_aml_opcode(walk_state); |
311 | if (status == AE_CTRL_PARSE_CONTINUE) { |
312 | return_ACPI_STATUS(AE_CTRL_PARSE_CONTINUE); |
313 | } |
314 | if (ACPI_FAILURE(status)) { |
315 | return_ACPI_STATUS(status); |
316 | } |
317 | |
318 | /* Create Op structure and append to parent's argument list */ |
319 | |
320 | walk_state->op_info = acpi_ps_get_opcode_info(opcode: walk_state->opcode); |
321 | op = acpi_ps_alloc_op(opcode: walk_state->opcode, aml: aml_op_start); |
322 | if (!op) { |
323 | return_ACPI_STATUS(AE_NO_MEMORY); |
324 | } |
325 | |
326 | if (walk_state->op_info->flags & AML_NAMED) { |
327 | status = |
328 | acpi_ps_build_named_op(walk_state, aml_op_start, unnamed_op: op, |
329 | op: &named_op); |
330 | acpi_ps_free_op(op); |
331 | |
332 | #ifdef ACPI_ASL_COMPILER |
333 | if (acpi_gbl_disasm_flag |
334 | && walk_state->opcode == AML_EXTERNAL_OP |
335 | && status == AE_NOT_FOUND) { |
336 | /* |
337 | * If parsing of AML_EXTERNAL_OP's name path fails, then skip |
338 | * past this opcode and keep parsing. This is a much better |
339 | * alternative than to abort the entire disassembler. At this |
340 | * point, the parser_state is at the end of the namepath of the |
341 | * external declaration opcode. Setting walk_state->Aml to |
342 | * walk_state->parser_state.Aml + 2 moves increments the |
343 | * walk_state->Aml past the object type and the paramcount of the |
344 | * external opcode. |
345 | */ |
346 | walk_state->aml = walk_state->parser_state.aml + 2; |
347 | walk_state->parser_state.aml = walk_state->aml; |
348 | return_ACPI_STATUS(AE_CTRL_PARSE_CONTINUE); |
349 | } |
350 | #endif |
351 | if (ACPI_FAILURE(status)) { |
352 | return_ACPI_STATUS(status); |
353 | } |
354 | |
355 | *new_op = named_op; |
356 | return_ACPI_STATUS(AE_OK); |
357 | } |
358 | |
359 | /* Not a named opcode, just allocate Op and append to parent */ |
360 | |
361 | if (walk_state->op_info->flags & AML_CREATE) { |
362 | /* |
363 | * Backup to beginning of create_XXXfield declaration |
364 | * body_length is unknown until we parse the body |
365 | */ |
366 | op->named.data = aml_op_start; |
367 | op->named.length = 0; |
368 | } |
369 | |
370 | if (walk_state->opcode == AML_BANK_FIELD_OP) { |
371 | /* |
372 | * Backup to beginning of bank_field declaration |
373 | * body_length is unknown until we parse the body |
374 | */ |
375 | op->named.data = aml_op_start; |
376 | op->named.length = 0; |
377 | } |
378 | |
379 | parent_scope = acpi_ps_get_parent_scope(state: &(walk_state->parser_state)); |
380 | acpi_ps_append_arg(op: parent_scope, arg: op); |
381 | |
382 | if (parent_scope) { |
383 | op_info = |
384 | acpi_ps_get_opcode_info(opcode: parent_scope->common.aml_opcode); |
385 | if (op_info->flags & AML_HAS_TARGET) { |
386 | argument_count = |
387 | acpi_ps_get_argument_count(op_type: op_info->type); |
388 | if (parent_scope->common.arg_list_length > |
389 | argument_count) { |
390 | op->common.flags |= ACPI_PARSEOP_TARGET; |
391 | } |
392 | } |
393 | |
394 | /* |
395 | * Special case for both Increment() and Decrement(), where |
396 | * the lone argument is both a source and a target. |
397 | */ |
398 | else if ((parent_scope->common.aml_opcode == AML_INCREMENT_OP) |
399 | || (parent_scope->common.aml_opcode == |
400 | AML_DECREMENT_OP)) { |
401 | op->common.flags |= ACPI_PARSEOP_TARGET; |
402 | } |
403 | } |
404 | |
405 | if (walk_state->descending_callback != NULL) { |
406 | /* |
407 | * Find the object. This will either insert the object into |
408 | * the namespace or simply look it up |
409 | */ |
410 | walk_state->op = *new_op = op; |
411 | |
412 | status = walk_state->descending_callback(walk_state, &op); |
413 | status = acpi_ps_next_parse_state(walk_state, op, callback_status: status); |
414 | if (status == AE_CTRL_PENDING) { |
415 | status = AE_CTRL_PARSE_PENDING; |
416 | } |
417 | } |
418 | |
419 | return_ACPI_STATUS(status); |
420 | } |
421 | |
422 | /******************************************************************************* |
423 | * |
424 | * FUNCTION: acpi_ps_complete_op |
425 | * |
426 | * PARAMETERS: walk_state - Current state |
427 | * op - Returned Op |
428 | * status - Parse status before complete Op |
429 | * |
430 | * RETURN: Status |
431 | * |
432 | * DESCRIPTION: Complete Op |
433 | * |
434 | ******************************************************************************/ |
435 | |
436 | acpi_status |
437 | acpi_ps_complete_op(struct acpi_walk_state *walk_state, |
438 | union acpi_parse_object **op, acpi_status status) |
439 | { |
440 | acpi_status status2; |
441 | |
442 | ACPI_FUNCTION_TRACE_PTR(ps_complete_op, walk_state); |
443 | |
444 | /* |
445 | * Finished one argument of the containing scope |
446 | */ |
447 | walk_state->parser_state.scope->parse_scope.arg_count--; |
448 | |
449 | /* Close this Op (will result in parse subtree deletion) */ |
450 | |
451 | status2 = acpi_ps_complete_this_op(walk_state, op: *op); |
452 | if (ACPI_FAILURE(status2)) { |
453 | return_ACPI_STATUS(status2); |
454 | } |
455 | |
456 | *op = NULL; |
457 | |
458 | switch (status) { |
459 | case AE_OK: |
460 | |
461 | break; |
462 | |
463 | case AE_CTRL_TRANSFER: |
464 | |
465 | /* We are about to transfer to a called method */ |
466 | |
467 | walk_state->prev_op = NULL; |
468 | walk_state->prev_arg_types = walk_state->arg_types; |
469 | return_ACPI_STATUS(status); |
470 | |
471 | case AE_CTRL_END: |
472 | |
473 | acpi_ps_pop_scope(parser_state: &(walk_state->parser_state), op, |
474 | arg_list: &walk_state->arg_types, |
475 | arg_count: &walk_state->arg_count); |
476 | |
477 | if (*op) { |
478 | walk_state->op = *op; |
479 | walk_state->op_info = |
480 | acpi_ps_get_opcode_info(opcode: (*op)->common.aml_opcode); |
481 | walk_state->opcode = (*op)->common.aml_opcode; |
482 | |
483 | status = walk_state->ascending_callback(walk_state); |
484 | (void)acpi_ps_next_parse_state(walk_state, op: *op, callback_status: status); |
485 | |
486 | status2 = acpi_ps_complete_this_op(walk_state, op: *op); |
487 | if (ACPI_FAILURE(status2)) { |
488 | return_ACPI_STATUS(status2); |
489 | } |
490 | } |
491 | |
492 | break; |
493 | |
494 | case AE_CTRL_BREAK: |
495 | case AE_CTRL_CONTINUE: |
496 | |
497 | /* Pop off scopes until we find the While */ |
498 | |
499 | while (!(*op) || ((*op)->common.aml_opcode != AML_WHILE_OP)) { |
500 | acpi_ps_pop_scope(parser_state: &(walk_state->parser_state), op, |
501 | arg_list: &walk_state->arg_types, |
502 | arg_count: &walk_state->arg_count); |
503 | } |
504 | |
505 | /* Close this iteration of the While loop */ |
506 | |
507 | walk_state->op = *op; |
508 | walk_state->op_info = |
509 | acpi_ps_get_opcode_info(opcode: (*op)->common.aml_opcode); |
510 | walk_state->opcode = (*op)->common.aml_opcode; |
511 | |
512 | status = walk_state->ascending_callback(walk_state); |
513 | (void)acpi_ps_next_parse_state(walk_state, op: *op, callback_status: status); |
514 | |
515 | status2 = acpi_ps_complete_this_op(walk_state, op: *op); |
516 | if (ACPI_FAILURE(status2)) { |
517 | return_ACPI_STATUS(status2); |
518 | } |
519 | |
520 | break; |
521 | |
522 | case AE_CTRL_TERMINATE: |
523 | |
524 | /* Clean up */ |
525 | do { |
526 | if (*op) { |
527 | status2 = |
528 | acpi_ps_complete_this_op(walk_state, op: *op); |
529 | if (ACPI_FAILURE(status2)) { |
530 | return_ACPI_STATUS(status2); |
531 | } |
532 | |
533 | acpi_ut_delete_generic_state |
534 | (state: acpi_ut_pop_generic_state |
535 | (list_head: &walk_state->control_state)); |
536 | } |
537 | |
538 | acpi_ps_pop_scope(parser_state: &(walk_state->parser_state), op, |
539 | arg_list: &walk_state->arg_types, |
540 | arg_count: &walk_state->arg_count); |
541 | |
542 | } while (*op); |
543 | |
544 | return_ACPI_STATUS(AE_OK); |
545 | |
546 | default: /* All other non-AE_OK status */ |
547 | |
548 | do { |
549 | if (*op) { |
550 | /* |
551 | * These Opcodes need to be removed from the namespace because they |
552 | * get created even if these opcodes cannot be created due to |
553 | * errors. |
554 | */ |
555 | if (((*op)->common.aml_opcode == AML_REGION_OP) |
556 | || ((*op)->common.aml_opcode == |
557 | AML_DATA_REGION_OP)) { |
558 | acpi_ns_delete_children(parent: (*op)->common. |
559 | node); |
560 | acpi_ns_remove_node(node: (*op)->common.node); |
561 | (*op)->common.node = NULL; |
562 | acpi_ps_delete_parse_tree(root: *op); |
563 | } |
564 | |
565 | status2 = |
566 | acpi_ps_complete_this_op(walk_state, op: *op); |
567 | if (ACPI_FAILURE(status2)) { |
568 | return_ACPI_STATUS(status2); |
569 | } |
570 | } |
571 | |
572 | acpi_ps_pop_scope(parser_state: &(walk_state->parser_state), op, |
573 | arg_list: &walk_state->arg_types, |
574 | arg_count: &walk_state->arg_count); |
575 | |
576 | } while (*op); |
577 | |
578 | #if 0 |
579 | /* |
580 | * TBD: Cleanup parse ops on error |
581 | */ |
582 | if (*op == NULL) { |
583 | acpi_ps_pop_scope(parser_state, op, |
584 | &walk_state->arg_types, |
585 | &walk_state->arg_count); |
586 | } |
587 | #endif |
588 | walk_state->prev_op = NULL; |
589 | walk_state->prev_arg_types = walk_state->arg_types; |
590 | |
591 | if (walk_state->parse_flags & ACPI_PARSE_MODULE_LEVEL) { |
592 | /* |
593 | * There was something that went wrong while executing code at the |
594 | * module-level. We need to skip parsing whatever caused the |
595 | * error and keep going. One runtime error during the table load |
596 | * should not cause the entire table to not be loaded. This is |
597 | * because there could be correct AML beyond the parts that caused |
598 | * the runtime error. |
599 | */ |
600 | ACPI_INFO(("Ignoring error and continuing table load" )); |
601 | return_ACPI_STATUS(AE_OK); |
602 | } |
603 | return_ACPI_STATUS(status); |
604 | } |
605 | |
606 | /* This scope complete? */ |
607 | |
608 | if (acpi_ps_has_completed_scope(parser_state: &(walk_state->parser_state))) { |
609 | acpi_ps_pop_scope(parser_state: &(walk_state->parser_state), op, |
610 | arg_list: &walk_state->arg_types, |
611 | arg_count: &walk_state->arg_count); |
612 | ACPI_DEBUG_PRINT((ACPI_DB_PARSE, "Popped scope, Op=%p\n" , *op)); |
613 | } else { |
614 | *op = NULL; |
615 | } |
616 | |
617 | return_ACPI_STATUS(AE_OK); |
618 | } |
619 | |
620 | /******************************************************************************* |
621 | * |
622 | * FUNCTION: acpi_ps_complete_final_op |
623 | * |
624 | * PARAMETERS: walk_state - Current state |
625 | * op - Current Op |
626 | * status - Current parse status before complete last |
627 | * Op |
628 | * |
629 | * RETURN: Status |
630 | * |
631 | * DESCRIPTION: Complete last Op. |
632 | * |
633 | ******************************************************************************/ |
634 | |
635 | acpi_status |
636 | acpi_ps_complete_final_op(struct acpi_walk_state *walk_state, |
637 | union acpi_parse_object *op, acpi_status status) |
638 | { |
639 | acpi_status status2; |
640 | |
641 | ACPI_FUNCTION_TRACE_PTR(ps_complete_final_op, walk_state); |
642 | |
643 | /* |
644 | * Complete the last Op (if not completed), and clear the scope stack. |
645 | * It is easily possible to end an AML "package" with an unbounded number |
646 | * of open scopes (such as when several ASL blocks are closed with |
647 | * sequential closing braces). We want to terminate each one cleanly. |
648 | */ |
649 | ACPI_DEBUG_PRINT((ACPI_DB_PARSE, "AML package complete at Op %p\n" , |
650 | op)); |
651 | do { |
652 | if (op) { |
653 | if (walk_state->ascending_callback != NULL) { |
654 | walk_state->op = op; |
655 | walk_state->op_info = |
656 | acpi_ps_get_opcode_info(opcode: op->common. |
657 | aml_opcode); |
658 | walk_state->opcode = op->common.aml_opcode; |
659 | |
660 | status = |
661 | walk_state->ascending_callback(walk_state); |
662 | status = |
663 | acpi_ps_next_parse_state(walk_state, op, |
664 | callback_status: status); |
665 | if (status == AE_CTRL_PENDING) { |
666 | status = |
667 | acpi_ps_complete_op(walk_state, op: &op, |
668 | AE_OK); |
669 | if (ACPI_FAILURE(status)) { |
670 | return_ACPI_STATUS(status); |
671 | } |
672 | } |
673 | |
674 | if (status == AE_CTRL_TERMINATE) { |
675 | status = AE_OK; |
676 | |
677 | /* Clean up */ |
678 | do { |
679 | if (op) { |
680 | status2 = |
681 | acpi_ps_complete_this_op |
682 | (walk_state, op); |
683 | if (ACPI_FAILURE |
684 | (status2)) { |
685 | return_ACPI_STATUS |
686 | (status2); |
687 | } |
688 | } |
689 | |
690 | acpi_ps_pop_scope(parser_state: & |
691 | (walk_state-> |
692 | parser_state), |
693 | op: &op, |
694 | arg_list: &walk_state-> |
695 | arg_types, |
696 | arg_count: &walk_state-> |
697 | arg_count); |
698 | |
699 | } while (op); |
700 | |
701 | return_ACPI_STATUS(status); |
702 | } |
703 | |
704 | else if (ACPI_FAILURE(status)) { |
705 | |
706 | /* First error is most important */ |
707 | |
708 | (void) |
709 | acpi_ps_complete_this_op(walk_state, |
710 | op); |
711 | return_ACPI_STATUS(status); |
712 | } |
713 | } |
714 | |
715 | status2 = acpi_ps_complete_this_op(walk_state, op); |
716 | if (ACPI_FAILURE(status2)) { |
717 | return_ACPI_STATUS(status2); |
718 | } |
719 | } |
720 | |
721 | acpi_ps_pop_scope(parser_state: &(walk_state->parser_state), op: &op, |
722 | arg_list: &walk_state->arg_types, |
723 | arg_count: &walk_state->arg_count); |
724 | |
725 | } while (op); |
726 | |
727 | return_ACPI_STATUS(status); |
728 | } |
729 | |