Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /****************************************************************************** |
2 | * | |
3 | * Module Name: psparse - Parser top level AML parse routines | |
4 | * | |
5 | *****************************************************************************/ | |
6 | ||
7 | /* | |
8 | * Copyright (C) 2000 - 2005, R. Byron Moore | |
9 | * All rights reserved. | |
10 | * | |
11 | * Redistribution and use in source and binary forms, with or without | |
12 | * modification, are permitted provided that the following conditions | |
13 | * are met: | |
14 | * 1. Redistributions of source code must retain the above copyright | |
15 | * notice, this list of conditions, and the following disclaimer, | |
16 | * without modification. | |
17 | * 2. Redistributions in binary form must reproduce at minimum a disclaimer | |
18 | * substantially similar to the "NO WARRANTY" disclaimer below | |
19 | * ("Disclaimer") and any redistribution must be conditioned upon | |
20 | * including a substantially similar Disclaimer requirement for further | |
21 | * binary redistribution. | |
22 | * 3. Neither the names of the above-listed copyright holders nor the names | |
23 | * of any contributors may be used to endorse or promote products derived | |
24 | * from this software without specific prior written permission. | |
25 | * | |
26 | * Alternatively, this software may be distributed under the terms of the | |
27 | * GNU General Public License ("GPL") version 2 as published by the Free | |
28 | * Software Foundation. | |
29 | * | |
30 | * NO WARRANTY | |
31 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
32 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
33 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR | |
34 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
35 | * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
36 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
37 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
38 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | |
39 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING | |
40 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
41 | * POSSIBILITY OF SUCH DAMAGES. | |
42 | */ | |
43 | ||
44 | ||
45 | /* | |
46 | * Parse the AML and build an operation tree as most interpreters, | |
47 | * like Perl, do. Parsing is done by hand rather than with a YACC | |
48 | * generated parser to tightly constrain stack and dynamic memory | |
49 | * usage. At the same time, parsing is kept flexible and the code | |
50 | * fairly compact by parsing based on a list of AML opcode | |
51 | * templates in aml_op_info[] | |
52 | */ | |
53 | ||
54 | #include <acpi/acpi.h> | |
55 | #include <acpi/acparser.h> | |
56 | #include <acpi/acdispat.h> | |
57 | #include <acpi/amlcode.h> | |
58 | #include <acpi/acnamesp.h> | |
59 | #include <acpi/acinterp.h> | |
60 | ||
61 | #define _COMPONENT ACPI_PARSER | |
62 | ACPI_MODULE_NAME ("psparse") | |
63 | ||
64 | ||
65 | static u32 acpi_gbl_depth = 0; | |
66 | ||
44f6c012 RM |
67 | /* Local prototypes */ |
68 | ||
69 | static void | |
70 | acpi_ps_complete_this_op ( | |
71 | struct acpi_walk_state *walk_state, | |
72 | union acpi_parse_object *op); | |
73 | ||
74 | static acpi_status | |
75 | acpi_ps_next_parse_state ( | |
76 | struct acpi_walk_state *walk_state, | |
77 | union acpi_parse_object *op, | |
78 | acpi_status callback_status); | |
79 | ||
80 | static acpi_status | |
81 | acpi_ps_parse_loop ( | |
82 | struct acpi_walk_state *walk_state); | |
83 | ||
1da177e4 LT |
84 | |
85 | /******************************************************************************* | |
86 | * | |
87 | * FUNCTION: acpi_ps_get_opcode_size | |
88 | * | |
89 | * PARAMETERS: Opcode - An AML opcode | |
90 | * | |
91 | * RETURN: Size of the opcode, in bytes (1 or 2) | |
92 | * | |
93 | * DESCRIPTION: Get the size of the current opcode. | |
94 | * | |
95 | ******************************************************************************/ | |
96 | ||
97 | u32 | |
98 | acpi_ps_get_opcode_size ( | |
99 | u32 opcode) | |
100 | { | |
101 | ||
102 | /* Extended (2-byte) opcode if > 255 */ | |
103 | ||
104 | if (opcode > 0x00FF) { | |
105 | return (2); | |
106 | } | |
107 | ||
108 | /* Otherwise, just a single byte opcode */ | |
109 | ||
110 | return (1); | |
111 | } | |
112 | ||
113 | ||
114 | /******************************************************************************* | |
115 | * | |
116 | * FUNCTION: acpi_ps_peek_opcode | |
117 | * | |
118 | * PARAMETERS: parser_state - A parser state object | |
119 | * | |
44f6c012 | 120 | * RETURN: Next AML opcode |
1da177e4 LT |
121 | * |
122 | * DESCRIPTION: Get next AML opcode (without incrementing AML pointer) | |
123 | * | |
124 | ******************************************************************************/ | |
125 | ||
126 | u16 | |
127 | acpi_ps_peek_opcode ( | |
128 | struct acpi_parse_state *parser_state) | |
129 | { | |
130 | u8 *aml; | |
131 | u16 opcode; | |
132 | ||
133 | ||
134 | aml = parser_state->aml; | |
135 | opcode = (u16) ACPI_GET8 (aml); | |
136 | ||
1da177e4 LT |
137 | if (opcode == AML_EXTOP) { |
138 | /* Extended opcode */ | |
139 | ||
140 | aml++; | |
141 | opcode = (u16) ((opcode << 8) | ACPI_GET8 (aml)); | |
142 | } | |
143 | ||
144 | return (opcode); | |
145 | } | |
146 | ||
147 | ||
148 | /******************************************************************************* | |
149 | * | |
150 | * FUNCTION: acpi_ps_complete_this_op | |
151 | * | |
152 | * PARAMETERS: walk_state - Current State | |
153 | * Op - Op to complete | |
154 | * | |
155 | * RETURN: None. | |
156 | * | |
157 | * DESCRIPTION: Perform any cleanup at the completion of an Op. | |
158 | * | |
159 | ******************************************************************************/ | |
160 | ||
44f6c012 | 161 | static void |
1da177e4 LT |
162 | acpi_ps_complete_this_op ( |
163 | struct acpi_walk_state *walk_state, | |
164 | union acpi_parse_object *op) | |
165 | { | |
166 | union acpi_parse_object *prev; | |
167 | union acpi_parse_object *next; | |
168 | const struct acpi_opcode_info *parent_info; | |
169 | union acpi_parse_object *replacement_op = NULL; | |
170 | ||
171 | ||
172 | ACPI_FUNCTION_TRACE_PTR ("ps_complete_this_op", op); | |
173 | ||
174 | ||
175 | /* Check for null Op, can happen if AML code is corrupt */ | |
176 | ||
177 | if (!op) { | |
178 | return_VOID; | |
179 | } | |
180 | ||
181 | /* Delete this op and the subtree below it if asked to */ | |
182 | ||
183 | if (((walk_state->parse_flags & ACPI_PARSE_TREE_MASK) != ACPI_PARSE_DELETE_TREE) || | |
184 | (walk_state->op_info->class == AML_CLASS_ARGUMENT)) { | |
185 | return_VOID; | |
186 | } | |
187 | ||
188 | /* Make sure that we only delete this subtree */ | |
189 | ||
190 | if (op->common.parent) { | |
191 | /* | |
192 | * Check if we need to replace the operator and its subtree | |
193 | * with a return value op (placeholder op) | |
194 | */ | |
195 | parent_info = acpi_ps_get_opcode_info (op->common.parent->common.aml_opcode); | |
196 | ||
197 | switch (parent_info->class) { | |
198 | case AML_CLASS_CONTROL: | |
199 | break; | |
200 | ||
201 | case AML_CLASS_CREATE: | |
202 | ||
203 | /* | |
204 | * These opcodes contain term_arg operands. The current | |
205 | * op must be replaced by a placeholder return op | |
206 | */ | |
207 | replacement_op = acpi_ps_alloc_op (AML_INT_RETURN_VALUE_OP); | |
208 | if (!replacement_op) { | |
209 | goto cleanup; | |
210 | } | |
211 | break; | |
212 | ||
213 | case AML_CLASS_NAMED_OBJECT: | |
214 | ||
215 | /* | |
216 | * These opcodes contain term_arg operands. The current | |
217 | * op must be replaced by a placeholder return op | |
218 | */ | |
219 | if ((op->common.parent->common.aml_opcode == AML_REGION_OP) || | |
220 | (op->common.parent->common.aml_opcode == AML_DATA_REGION_OP) || | |
221 | (op->common.parent->common.aml_opcode == AML_BUFFER_OP) || | |
222 | (op->common.parent->common.aml_opcode == AML_PACKAGE_OP) || | |
223 | (op->common.parent->common.aml_opcode == AML_VAR_PACKAGE_OP)) { | |
224 | replacement_op = acpi_ps_alloc_op (AML_INT_RETURN_VALUE_OP); | |
225 | if (!replacement_op) { | |
226 | goto cleanup; | |
227 | } | |
228 | } | |
229 | ||
230 | if ((op->common.parent->common.aml_opcode == AML_NAME_OP) && | |
231 | (walk_state->descending_callback != acpi_ds_exec_begin_op)) { | |
232 | if ((op->common.aml_opcode == AML_BUFFER_OP) || | |
233 | (op->common.aml_opcode == AML_PACKAGE_OP) || | |
234 | (op->common.aml_opcode == AML_VAR_PACKAGE_OP)) { | |
235 | replacement_op = acpi_ps_alloc_op (op->common.aml_opcode); | |
236 | if (!replacement_op) { | |
237 | goto cleanup; | |
238 | } | |
239 | ||
240 | replacement_op->named.data = op->named.data; | |
241 | replacement_op->named.length = op->named.length; | |
242 | } | |
243 | } | |
244 | break; | |
245 | ||
246 | default: | |
247 | replacement_op = acpi_ps_alloc_op (AML_INT_RETURN_VALUE_OP); | |
248 | if (!replacement_op) { | |
249 | goto cleanup; | |
250 | } | |
251 | } | |
252 | ||
253 | /* We must unlink this op from the parent tree */ | |
254 | ||
255 | prev = op->common.parent->common.value.arg; | |
256 | if (prev == op) { | |
257 | /* This op is the first in the list */ | |
258 | ||
259 | if (replacement_op) { | |
260 | replacement_op->common.parent = op->common.parent; | |
261 | replacement_op->common.value.arg = NULL; | |
262 | replacement_op->common.node = op->common.node; | |
263 | op->common.parent->common.value.arg = replacement_op; | |
264 | replacement_op->common.next = op->common.next; | |
265 | } | |
266 | else { | |
267 | op->common.parent->common.value.arg = op->common.next; | |
268 | } | |
269 | } | |
270 | ||
271 | /* Search the parent list */ | |
272 | ||
273 | else while (prev) { | |
274 | /* Traverse all siblings in the parent's argument list */ | |
275 | ||
276 | next = prev->common.next; | |
277 | if (next == op) { | |
278 | if (replacement_op) { | |
279 | replacement_op->common.parent = op->common.parent; | |
280 | replacement_op->common.value.arg = NULL; | |
281 | replacement_op->common.node = op->common.node; | |
282 | prev->common.next = replacement_op; | |
283 | replacement_op->common.next = op->common.next; | |
284 | next = NULL; | |
285 | } | |
286 | else { | |
287 | prev->common.next = op->common.next; | |
288 | next = NULL; | |
289 | } | |
290 | } | |
1da177e4 LT |
291 | prev = next; |
292 | } | |
293 | } | |
294 | ||
295 | ||
296 | cleanup: | |
297 | ||
44f6c012 | 298 | /* Now we can actually delete the subtree rooted at Op */ |
1da177e4 LT |
299 | |
300 | acpi_ps_delete_parse_tree (op); | |
301 | return_VOID; | |
302 | } | |
303 | ||
304 | ||
305 | /******************************************************************************* | |
306 | * | |
307 | * FUNCTION: acpi_ps_next_parse_state | |
308 | * | |
44f6c012 RM |
309 | * PARAMETERS: walk_state - Current state |
310 | * Op - Current parse op | |
311 | * callback_status - Status from previous operation | |
1da177e4 LT |
312 | * |
313 | * RETURN: Status | |
314 | * | |
315 | * DESCRIPTION: Update the parser state based upon the return exception from | |
316 | * the parser callback. | |
317 | * | |
318 | ******************************************************************************/ | |
319 | ||
44f6c012 | 320 | static acpi_status |
1da177e4 LT |
321 | acpi_ps_next_parse_state ( |
322 | struct acpi_walk_state *walk_state, | |
323 | union acpi_parse_object *op, | |
324 | acpi_status callback_status) | |
325 | { | |
326 | struct acpi_parse_state *parser_state = &walk_state->parser_state; | |
327 | acpi_status status = AE_CTRL_PENDING; | |
328 | ||
329 | ||
330 | ACPI_FUNCTION_TRACE_PTR ("ps_next_parse_state", op); | |
331 | ||
332 | ||
333 | switch (callback_status) { | |
334 | case AE_CTRL_TERMINATE: | |
335 | ||
336 | /* | |
337 | * A control method was terminated via a RETURN statement. | |
338 | * The walk of this method is complete. | |
339 | */ | |
340 | parser_state->aml = parser_state->aml_end; | |
341 | status = AE_CTRL_TERMINATE; | |
342 | break; | |
343 | ||
344 | ||
345 | case AE_CTRL_BREAK: | |
346 | ||
347 | parser_state->aml = walk_state->aml_last_while; | |
348 | walk_state->control_state->common.value = FALSE; | |
349 | status = AE_CTRL_BREAK; | |
350 | break; | |
351 | ||
352 | case AE_CTRL_CONTINUE: | |
353 | ||
354 | ||
355 | parser_state->aml = walk_state->aml_last_while; | |
356 | status = AE_CTRL_CONTINUE; | |
357 | break; | |
358 | ||
359 | case AE_CTRL_PENDING: | |
360 | ||
361 | parser_state->aml = walk_state->aml_last_while; | |
362 | break; | |
363 | ||
364 | #if 0 | |
365 | case AE_CTRL_SKIP: | |
366 | ||
367 | parser_state->aml = parser_state->scope->parse_scope.pkg_end; | |
368 | status = AE_OK; | |
369 | break; | |
370 | #endif | |
371 | ||
372 | case AE_CTRL_TRUE: | |
373 | ||
374 | /* | |
375 | * Predicate of an IF was true, and we are at the matching ELSE. | |
376 | * Just close out this package | |
377 | */ | |
378 | parser_state->aml = acpi_ps_get_next_package_end (parser_state); | |
379 | break; | |
380 | ||
381 | ||
382 | case AE_CTRL_FALSE: | |
383 | ||
384 | /* | |
385 | * Either an IF/WHILE Predicate was false or we encountered a BREAK | |
386 | * opcode. In both cases, we do not execute the rest of the | |
387 | * package; We simply close out the parent (finishing the walk of | |
388 | * this branch of the tree) and continue execution at the parent | |
389 | * level. | |
390 | */ | |
391 | parser_state->aml = parser_state->scope->parse_scope.pkg_end; | |
392 | ||
393 | /* In the case of a BREAK, just force a predicate (if any) to FALSE */ | |
394 | ||
395 | walk_state->control_state->common.value = FALSE; | |
396 | status = AE_CTRL_END; | |
397 | break; | |
398 | ||
399 | ||
400 | case AE_CTRL_TRANSFER: | |
401 | ||
44f6c012 RM |
402 | /* A method call (invocation) -- transfer control */ |
403 | ||
1da177e4 LT |
404 | status = AE_CTRL_TRANSFER; |
405 | walk_state->prev_op = op; | |
406 | walk_state->method_call_op = op; | |
407 | walk_state->method_call_node = (op->common.value.arg)->common.node; | |
408 | ||
409 | /* Will return value (if any) be used by the caller? */ | |
410 | ||
411 | walk_state->return_used = acpi_ds_is_result_used (op, walk_state); | |
412 | break; | |
413 | ||
414 | ||
415 | default: | |
44f6c012 | 416 | |
1da177e4 LT |
417 | status = callback_status; |
418 | if ((callback_status & AE_CODE_MASK) == AE_CODE_CONTROL) { | |
419 | status = AE_OK; | |
420 | } | |
421 | break; | |
422 | } | |
423 | ||
424 | return_ACPI_STATUS (status); | |
425 | } | |
426 | ||
427 | ||
428 | /******************************************************************************* | |
429 | * | |
430 | * FUNCTION: acpi_ps_parse_loop | |
431 | * | |
44f6c012 | 432 | * PARAMETERS: walk_state - Current state |
1da177e4 LT |
433 | * |
434 | * RETURN: Status | |
435 | * | |
436 | * DESCRIPTION: Parse AML (pointed to by the current parser state) and return | |
437 | * a tree of ops. | |
438 | * | |
439 | ******************************************************************************/ | |
440 | ||
44f6c012 | 441 | static acpi_status |
1da177e4 LT |
442 | acpi_ps_parse_loop ( |
443 | struct acpi_walk_state *walk_state) | |
444 | { | |
445 | acpi_status status = AE_OK; | |
446 | union acpi_parse_object *op = NULL; /* current op */ | |
447 | union acpi_parse_object *arg = NULL; | |
448 | union acpi_parse_object *pre_op = NULL; | |
449 | struct acpi_parse_state *parser_state; | |
450 | u8 *aml_op_start = NULL; | |
451 | ||
452 | ||
453 | ACPI_FUNCTION_TRACE_PTR ("ps_parse_loop", walk_state); | |
454 | ||
455 | if (walk_state->descending_callback == NULL) { | |
456 | return_ACPI_STATUS (AE_BAD_PARAMETER); | |
457 | } | |
458 | ||
459 | parser_state = &walk_state->parser_state; | |
460 | walk_state->arg_types = 0; | |
461 | ||
462 | #if (!defined (ACPI_NO_METHOD_EXECUTION) && !defined (ACPI_CONSTANT_EVAL_ONLY)) | |
44f6c012 | 463 | |
1da177e4 LT |
464 | if (walk_state->walk_type & ACPI_WALK_METHOD_RESTART) { |
465 | /* We are restarting a preempted control method */ | |
466 | ||
467 | if (acpi_ps_has_completed_scope (parser_state)) { | |
468 | /* | |
469 | * We must check if a predicate to an IF or WHILE statement | |
470 | * was just completed | |
471 | */ | |
472 | if ((parser_state->scope->parse_scope.op) && | |
473 | ((parser_state->scope->parse_scope.op->common.aml_opcode == AML_IF_OP) || | |
474 | (parser_state->scope->parse_scope.op->common.aml_opcode == AML_WHILE_OP)) && | |
475 | (walk_state->control_state) && | |
476 | (walk_state->control_state->common.state == | |
477 | ACPI_CONTROL_PREDICATE_EXECUTING)) { | |
478 | /* | |
479 | * A predicate was just completed, get the value of the | |
480 | * predicate and branch based on that value | |
481 | */ | |
482 | walk_state->op = NULL; | |
483 | status = acpi_ds_get_predicate_value (walk_state, ACPI_TO_POINTER (TRUE)); | |
484 | if (ACPI_FAILURE (status) && | |
485 | ((status & AE_CODE_MASK) != AE_CODE_CONTROL)) { | |
486 | if (status == AE_AML_NO_RETURN_VALUE) { | |
487 | ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, | |
488 | "Invoked method did not return a value, %s\n", | |
489 | acpi_format_exception (status))); | |
490 | ||
491 | } | |
44f6c012 RM |
492 | ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, |
493 | "get_predicate Failed, %s\n", | |
1da177e4 LT |
494 | acpi_format_exception (status))); |
495 | return_ACPI_STATUS (status); | |
496 | } | |
497 | ||
498 | status = acpi_ps_next_parse_state (walk_state, op, status); | |
499 | } | |
500 | ||
501 | acpi_ps_pop_scope (parser_state, &op, | |
502 | &walk_state->arg_types, &walk_state->arg_count); | |
503 | ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "Popped scope, Op=%p\n", op)); | |
504 | } | |
505 | else if (walk_state->prev_op) { | |
506 | /* We were in the middle of an op */ | |
507 | ||
508 | op = walk_state->prev_op; | |
509 | walk_state->arg_types = walk_state->prev_arg_types; | |
510 | } | |
511 | } | |
512 | #endif | |
513 | ||
44f6c012 RM |
514 | /* Iterative parsing loop, while there is more AML to process: */ |
515 | ||
1da177e4 LT |
516 | while ((parser_state->aml < parser_state->aml_end) || (op)) { |
517 | aml_op_start = parser_state->aml; | |
518 | if (!op) { | |
519 | /* Get the next opcode from the AML stream */ | |
520 | ||
521 | walk_state->aml_offset = (u32) ACPI_PTR_DIFF (parser_state->aml, | |
44f6c012 | 522 | parser_state->aml_start); |
1da177e4 LT |
523 | walk_state->opcode = acpi_ps_peek_opcode (parser_state); |
524 | ||
525 | /* | |
526 | * First cut to determine what we have found: | |
527 | * 1) A valid AML opcode | |
528 | * 2) A name string | |
529 | * 3) An unknown/invalid opcode | |
530 | */ | |
531 | walk_state->op_info = acpi_ps_get_opcode_info (walk_state->opcode); | |
532 | switch (walk_state->op_info->class) { | |
533 | case AML_CLASS_ASCII: | |
534 | case AML_CLASS_PREFIX: | |
535 | /* | |
536 | * Starts with a valid prefix or ASCII char, this is a name | |
537 | * string. Convert the bare name string to a namepath. | |
538 | */ | |
539 | walk_state->opcode = AML_INT_NAMEPATH_OP; | |
540 | walk_state->arg_types = ARGP_NAMESTRING; | |
541 | break; | |
542 | ||
543 | case AML_CLASS_UNKNOWN: | |
544 | ||
545 | /* The opcode is unrecognized. Just skip unknown opcodes */ | |
546 | ||
547 | ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, | |
548 | "Found unknown opcode %X at AML address %p offset %X, ignoring\n", | |
549 | walk_state->opcode, parser_state->aml, walk_state->aml_offset)); | |
550 | ||
551 | ACPI_DUMP_BUFFER (parser_state->aml, 128); | |
552 | ||
553 | /* Assume one-byte bad opcode */ | |
554 | ||
555 | parser_state->aml++; | |
556 | continue; | |
557 | ||
558 | default: | |
559 | ||
560 | /* Found opcode info, this is a normal opcode */ | |
561 | ||
562 | parser_state->aml += acpi_ps_get_opcode_size (walk_state->opcode); | |
563 | walk_state->arg_types = walk_state->op_info->parse_args; | |
564 | break; | |
565 | } | |
566 | ||
567 | /* Create Op structure and append to parent's argument list */ | |
568 | ||
569 | if (walk_state->op_info->flags & AML_NAMED) { | |
570 | /* Allocate a new pre_op if necessary */ | |
571 | ||
572 | if (!pre_op) { | |
573 | pre_op = acpi_ps_alloc_op (walk_state->opcode); | |
574 | if (!pre_op) { | |
575 | status = AE_NO_MEMORY; | |
576 | goto close_this_op; | |
577 | } | |
578 | } | |
579 | ||
580 | pre_op->common.value.arg = NULL; | |
581 | pre_op->common.aml_opcode = walk_state->opcode; | |
582 | ||
583 | /* | |
584 | * Get and append arguments until we find the node that contains | |
585 | * the name (the type ARGP_NAME). | |
586 | */ | |
587 | while (GET_CURRENT_ARG_TYPE (walk_state->arg_types) && | |
588 | (GET_CURRENT_ARG_TYPE (walk_state->arg_types) != ARGP_NAME)) { | |
589 | status = acpi_ps_get_next_arg (walk_state, parser_state, | |
590 | GET_CURRENT_ARG_TYPE (walk_state->arg_types), &arg); | |
591 | if (ACPI_FAILURE (status)) { | |
592 | goto close_this_op; | |
593 | } | |
594 | ||
595 | acpi_ps_append_arg (pre_op, arg); | |
596 | INCREMENT_ARG_LIST (walk_state->arg_types); | |
597 | } | |
598 | ||
44f6c012 RM |
599 | /* |
600 | * Make sure that we found a NAME and didn't run out of | |
601 | * arguments | |
602 | */ | |
1da177e4 LT |
603 | if (!GET_CURRENT_ARG_TYPE (walk_state->arg_types)) { |
604 | status = AE_AML_NO_OPERAND; | |
605 | goto close_this_op; | |
606 | } | |
607 | ||
608 | /* We know that this arg is a name, move to next arg */ | |
609 | ||
610 | INCREMENT_ARG_LIST (walk_state->arg_types); | |
611 | ||
612 | /* | |
613 | * Find the object. This will either insert the object into | |
614 | * the namespace or simply look it up | |
615 | */ | |
616 | walk_state->op = NULL; | |
617 | ||
618 | status = walk_state->descending_callback (walk_state, &op); | |
619 | if (ACPI_FAILURE (status)) { | |
44f6c012 RM |
620 | ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, |
621 | "During name lookup/catalog, %s\n", | |
622 | acpi_format_exception (status))); | |
1da177e4 LT |
623 | goto close_this_op; |
624 | } | |
625 | ||
44f6c012 | 626 | if (!op) { |
1da177e4 LT |
627 | continue; |
628 | } | |
629 | ||
630 | status = acpi_ps_next_parse_state (walk_state, op, status); | |
631 | if (status == AE_CTRL_PENDING) { | |
632 | status = AE_OK; | |
633 | goto close_this_op; | |
634 | } | |
635 | ||
636 | if (ACPI_FAILURE (status)) { | |
637 | goto close_this_op; | |
638 | } | |
639 | ||
640 | acpi_ps_append_arg (op, pre_op->common.value.arg); | |
641 | acpi_gbl_depth++; | |
642 | ||
643 | if (op->common.aml_opcode == AML_REGION_OP) { | |
644 | /* | |
645 | * Defer final parsing of an operation_region body, | |
646 | * because we don't have enough info in the first pass | |
647 | * to parse it correctly (i.e., there may be method | |
648 | * calls within the term_arg elements of the body.) | |
649 | * | |
650 | * However, we must continue parsing because | |
651 | * the opregion is not a standalone package -- | |
652 | * we don't know where the end is at this point. | |
653 | * | |
654 | * (Length is unknown until parse of the body complete) | |
655 | */ | |
656 | op->named.data = aml_op_start; | |
657 | op->named.length = 0; | |
658 | } | |
659 | } | |
660 | else { | |
661 | /* Not a named opcode, just allocate Op and append to parent */ | |
662 | ||
663 | walk_state->op_info = acpi_ps_get_opcode_info (walk_state->opcode); | |
664 | op = acpi_ps_alloc_op (walk_state->opcode); | |
665 | if (!op) { | |
666 | status = AE_NO_MEMORY; | |
667 | goto close_this_op; | |
668 | } | |
669 | ||
670 | if (walk_state->op_info->flags & AML_CREATE) { | |
671 | /* | |
672 | * Backup to beginning of create_xXXfield declaration | |
673 | * body_length is unknown until we parse the body | |
674 | */ | |
675 | op->named.data = aml_op_start; | |
676 | op->named.length = 0; | |
677 | } | |
678 | ||
679 | acpi_ps_append_arg (acpi_ps_get_parent_scope (parser_state), op); | |
680 | ||
681 | if ((walk_state->descending_callback != NULL)) { | |
682 | /* | |
44f6c012 | 683 | * Find the object. This will either insert the object into |
1da177e4 LT |
684 | * the namespace or simply look it up |
685 | */ | |
686 | walk_state->op = op; | |
687 | ||
688 | status = walk_state->descending_callback (walk_state, &op); | |
689 | status = acpi_ps_next_parse_state (walk_state, op, status); | |
690 | if (status == AE_CTRL_PENDING) { | |
691 | status = AE_OK; | |
692 | goto close_this_op; | |
693 | } | |
694 | ||
695 | if (ACPI_FAILURE (status)) { | |
696 | goto close_this_op; | |
697 | } | |
698 | } | |
699 | } | |
700 | ||
701 | op->common.aml_offset = walk_state->aml_offset; | |
702 | ||
703 | if (walk_state->op_info) { | |
704 | ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, | |
705 | "Opcode %4.4X [%s] Op %p Aml %p aml_offset %5.5X\n", | |
706 | (u32) op->common.aml_opcode, walk_state->op_info->name, | |
707 | op, parser_state->aml, op->common.aml_offset)); | |
708 | } | |
709 | } | |
710 | ||
711 | ||
44f6c012 RM |
712 | /* |
713 | * Start arg_count at zero because we don't know if there are | |
714 | * any args yet | |
715 | */ | |
1da177e4 LT |
716 | walk_state->arg_count = 0; |
717 | ||
44f6c012 RM |
718 | /* Are there any arguments that must be processed? */ |
719 | ||
720 | if (walk_state->arg_types) { | |
1da177e4 LT |
721 | /* Get arguments */ |
722 | ||
723 | switch (op->common.aml_opcode) { | |
724 | case AML_BYTE_OP: /* AML_BYTEDATA_ARG */ | |
725 | case AML_WORD_OP: /* AML_WORDDATA_ARG */ | |
726 | case AML_DWORD_OP: /* AML_DWORDATA_ARG */ | |
727 | case AML_QWORD_OP: /* AML_QWORDATA_ARG */ | |
728 | case AML_STRING_OP: /* AML_ASCIICHARLIST_ARG */ | |
729 | ||
730 | /* Fill in constant or string argument directly */ | |
731 | ||
732 | acpi_ps_get_next_simple_arg (parser_state, | |
733 | GET_CURRENT_ARG_TYPE (walk_state->arg_types), op); | |
734 | break; | |
735 | ||
736 | case AML_INT_NAMEPATH_OP: /* AML_NAMESTRING_ARG */ | |
737 | ||
738 | status = acpi_ps_get_next_namepath (walk_state, parser_state, op, 1); | |
739 | if (ACPI_FAILURE (status)) { | |
740 | goto close_this_op; | |
741 | } | |
742 | ||
743 | walk_state->arg_types = 0; | |
744 | break; | |
745 | ||
746 | default: | |
747 | ||
44f6c012 RM |
748 | /* |
749 | * Op is not a constant or string, append each argument | |
750 | * to the Op | |
751 | */ | |
1da177e4 LT |
752 | while (GET_CURRENT_ARG_TYPE (walk_state->arg_types) && |
753 | !walk_state->arg_count) { | |
44f6c012 RM |
754 | walk_state->aml_offset = (u32) |
755 | ACPI_PTR_DIFF (parser_state->aml, parser_state->aml_start); | |
756 | ||
1da177e4 | 757 | status = acpi_ps_get_next_arg (walk_state, parser_state, |
44f6c012 RM |
758 | GET_CURRENT_ARG_TYPE (walk_state->arg_types), |
759 | &arg); | |
1da177e4 LT |
760 | if (ACPI_FAILURE (status)) { |
761 | goto close_this_op; | |
762 | } | |
763 | ||
764 | if (arg) { | |
765 | arg->common.aml_offset = walk_state->aml_offset; | |
766 | acpi_ps_append_arg (op, arg); | |
767 | } | |
768 | INCREMENT_ARG_LIST (walk_state->arg_types); | |
769 | } | |
770 | ||
771 | /* Special processing for certain opcodes */ | |
772 | ||
773 | switch (op->common.aml_opcode) { | |
774 | case AML_METHOD_OP: | |
775 | ||
776 | /* | |
777 | * Skip parsing of control method | |
778 | * because we don't have enough info in the first pass | |
779 | * to parse it correctly. | |
780 | * | |
781 | * Save the length and address of the body | |
782 | */ | |
783 | op->named.data = parser_state->aml; | |
44f6c012 RM |
784 | op->named.length = (u32) (parser_state->pkg_end - |
785 | parser_state->aml); | |
1da177e4 LT |
786 | |
787 | /* Skip body of method */ | |
788 | ||
789 | parser_state->aml = parser_state->pkg_end; | |
790 | walk_state->arg_count = 0; | |
791 | break; | |
792 | ||
793 | case AML_BUFFER_OP: | |
794 | case AML_PACKAGE_OP: | |
795 | case AML_VAR_PACKAGE_OP: | |
796 | ||
797 | if ((op->common.parent) && | |
798 | (op->common.parent->common.aml_opcode == AML_NAME_OP) && | |
799 | (walk_state->descending_callback != acpi_ds_exec_begin_op)) { | |
800 | /* | |
801 | * Skip parsing of Buffers and Packages | |
802 | * because we don't have enough info in the first pass | |
803 | * to parse them correctly. | |
804 | */ | |
805 | op->named.data = aml_op_start; | |
44f6c012 RM |
806 | op->named.length = (u32) (parser_state->pkg_end - |
807 | aml_op_start); | |
1da177e4 LT |
808 | |
809 | /* Skip body */ | |
810 | ||
811 | parser_state->aml = parser_state->pkg_end; | |
812 | walk_state->arg_count = 0; | |
813 | } | |
814 | break; | |
815 | ||
816 | case AML_WHILE_OP: | |
817 | ||
818 | if (walk_state->control_state) { | |
44f6c012 RM |
819 | walk_state->control_state->control.package_end = |
820 | parser_state->pkg_end; | |
1da177e4 LT |
821 | } |
822 | break; | |
823 | ||
824 | default: | |
825 | ||
826 | /* No action for all other opcodes */ | |
827 | break; | |
828 | } | |
829 | break; | |
830 | } | |
831 | } | |
832 | ||
833 | /* Check for arguments that need to be processed */ | |
834 | ||
835 | if (walk_state->arg_count) { | |
44f6c012 RM |
836 | /* |
837 | * There are arguments (complex ones), push Op and | |
838 | * prepare for argument | |
839 | */ | |
1da177e4 LT |
840 | status = acpi_ps_push_scope (parser_state, op, |
841 | walk_state->arg_types, walk_state->arg_count); | |
842 | if (ACPI_FAILURE (status)) { | |
843 | goto close_this_op; | |
844 | } | |
845 | op = NULL; | |
846 | continue; | |
847 | } | |
848 | ||
44f6c012 RM |
849 | /* |
850 | * All arguments have been processed -- Op is complete, | |
851 | * prepare for next | |
852 | */ | |
1da177e4 LT |
853 | walk_state->op_info = acpi_ps_get_opcode_info (op->common.aml_opcode); |
854 | if (walk_state->op_info->flags & AML_NAMED) { | |
855 | if (acpi_gbl_depth) { | |
856 | acpi_gbl_depth--; | |
857 | } | |
858 | ||
859 | if (op->common.aml_opcode == AML_REGION_OP) { | |
860 | /* | |
861 | * Skip parsing of control method or opregion body, | |
862 | * because we don't have enough info in the first pass | |
863 | * to parse them correctly. | |
864 | * | |
865 | * Completed parsing an op_region declaration, we now | |
866 | * know the length. | |
867 | */ | |
868 | op->named.length = (u32) (parser_state->aml - op->named.data); | |
869 | } | |
870 | } | |
871 | ||
872 | if (walk_state->op_info->flags & AML_CREATE) { | |
873 | /* | |
874 | * Backup to beginning of create_xXXfield declaration (1 for | |
875 | * Opcode) | |
876 | * | |
877 | * body_length is unknown until we parse the body | |
878 | */ | |
879 | op->named.length = (u32) (parser_state->aml - op->named.data); | |
880 | } | |
881 | ||
882 | /* This op complete, notify the dispatcher */ | |
883 | ||
884 | if (walk_state->ascending_callback != NULL) { | |
885 | walk_state->op = op; | |
886 | walk_state->opcode = op->common.aml_opcode; | |
887 | ||
888 | status = walk_state->ascending_callback (walk_state); | |
889 | status = acpi_ps_next_parse_state (walk_state, op, status); | |
890 | if (status == AE_CTRL_PENDING) { | |
891 | status = AE_OK; | |
892 | goto close_this_op; | |
893 | } | |
894 | } | |
895 | ||
896 | ||
897 | close_this_op: | |
898 | /* | |
899 | * Finished one argument of the containing scope | |
900 | */ | |
901 | parser_state->scope->parse_scope.arg_count--; | |
902 | ||
903 | /* Close this Op (will result in parse subtree deletion) */ | |
904 | ||
905 | acpi_ps_complete_this_op (walk_state, op); | |
906 | op = NULL; | |
907 | if (pre_op) { | |
908 | acpi_ps_free_op (pre_op); | |
909 | pre_op = NULL; | |
910 | } | |
911 | ||
912 | switch (status) { | |
913 | case AE_OK: | |
914 | break; | |
915 | ||
916 | ||
917 | case AE_CTRL_TRANSFER: | |
918 | ||
44f6c012 RM |
919 | /* We are about to transfer to a called method. */ |
920 | ||
1da177e4 LT |
921 | walk_state->prev_op = op; |
922 | walk_state->prev_arg_types = walk_state->arg_types; | |
923 | return_ACPI_STATUS (status); | |
924 | ||
925 | ||
926 | case AE_CTRL_END: | |
927 | ||
928 | acpi_ps_pop_scope (parser_state, &op, | |
929 | &walk_state->arg_types, &walk_state->arg_count); | |
930 | ||
931 | if (op) { | |
932 | walk_state->op = op; | |
933 | walk_state->op_info = acpi_ps_get_opcode_info (op->common.aml_opcode); | |
934 | walk_state->opcode = op->common.aml_opcode; | |
935 | ||
936 | status = walk_state->ascending_callback (walk_state); | |
937 | status = acpi_ps_next_parse_state (walk_state, op, status); | |
938 | ||
939 | acpi_ps_complete_this_op (walk_state, op); | |
940 | op = NULL; | |
941 | } | |
942 | status = AE_OK; | |
943 | break; | |
944 | ||
945 | ||
946 | case AE_CTRL_BREAK: | |
947 | case AE_CTRL_CONTINUE: | |
948 | ||
949 | /* Pop off scopes until we find the While */ | |
950 | ||
951 | while (!op || (op->common.aml_opcode != AML_WHILE_OP)) { | |
952 | acpi_ps_pop_scope (parser_state, &op, | |
953 | &walk_state->arg_types, &walk_state->arg_count); | |
954 | } | |
955 | ||
956 | /* Close this iteration of the While loop */ | |
957 | ||
958 | walk_state->op = op; | |
959 | walk_state->op_info = acpi_ps_get_opcode_info (op->common.aml_opcode); | |
960 | walk_state->opcode = op->common.aml_opcode; | |
961 | ||
962 | status = walk_state->ascending_callback (walk_state); | |
963 | status = acpi_ps_next_parse_state (walk_state, op, status); | |
964 | ||
965 | acpi_ps_complete_this_op (walk_state, op); | |
966 | op = NULL; | |
967 | ||
968 | status = AE_OK; | |
969 | break; | |
970 | ||
971 | ||
972 | case AE_CTRL_TERMINATE: | |
973 | ||
974 | status = AE_OK; | |
975 | ||
976 | /* Clean up */ | |
977 | do { | |
978 | if (op) { | |
979 | acpi_ps_complete_this_op (walk_state, op); | |
980 | } | |
981 | acpi_ps_pop_scope (parser_state, &op, | |
982 | &walk_state->arg_types, &walk_state->arg_count); | |
983 | ||
984 | } while (op); | |
985 | ||
986 | return_ACPI_STATUS (status); | |
987 | ||
988 | ||
989 | default: /* All other non-AE_OK status */ | |
990 | ||
991 | do { | |
992 | if (op) { | |
993 | acpi_ps_complete_this_op (walk_state, op); | |
994 | } | |
995 | acpi_ps_pop_scope (parser_state, &op, | |
996 | &walk_state->arg_types, &walk_state->arg_count); | |
997 | ||
998 | } while (op); | |
999 | ||
1000 | ||
1001 | /* | |
1002 | * TBD: Cleanup parse ops on error | |
1003 | */ | |
1004 | #if 0 | |
1005 | if (op == NULL) { | |
1006 | acpi_ps_pop_scope (parser_state, &op, | |
1007 | &walk_state->arg_types, &walk_state->arg_count); | |
1008 | } | |
1009 | #endif | |
1010 | walk_state->prev_op = op; | |
1011 | walk_state->prev_arg_types = walk_state->arg_types; | |
1012 | return_ACPI_STATUS (status); | |
1013 | } | |
1014 | ||
1015 | /* This scope complete? */ | |
1016 | ||
1017 | if (acpi_ps_has_completed_scope (parser_state)) { | |
1018 | acpi_ps_pop_scope (parser_state, &op, | |
1019 | &walk_state->arg_types, &walk_state->arg_count); | |
1020 | ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "Popped scope, Op=%p\n", op)); | |
1021 | } | |
1022 | else { | |
1023 | op = NULL; | |
1024 | } | |
1025 | ||
1026 | } /* while parser_state->Aml */ | |
1027 | ||
1028 | ||
1029 | /* | |
1030 | * Complete the last Op (if not completed), and clear the scope stack. | |
1031 | * It is easily possible to end an AML "package" with an unbounded number | |
1032 | * of open scopes (such as when several ASL blocks are closed with | |
1033 | * sequential closing braces). We want to terminate each one cleanly. | |
1034 | */ | |
1035 | ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "AML package complete at Op %p\n", op)); | |
1036 | do { | |
1037 | if (op) { | |
1038 | if (walk_state->ascending_callback != NULL) { | |
1039 | walk_state->op = op; | |
1040 | walk_state->op_info = acpi_ps_get_opcode_info (op->common.aml_opcode); | |
1041 | walk_state->opcode = op->common.aml_opcode; | |
1042 | ||
1043 | status = walk_state->ascending_callback (walk_state); | |
1044 | status = acpi_ps_next_parse_state (walk_state, op, status); | |
1045 | if (status == AE_CTRL_PENDING) { | |
1046 | status = AE_OK; | |
1047 | goto close_this_op; | |
1048 | } | |
1049 | ||
1050 | if (status == AE_CTRL_TERMINATE) { | |
1051 | status = AE_OK; | |
1052 | ||
1053 | /* Clean up */ | |
1054 | do { | |
1055 | if (op) { | |
1056 | acpi_ps_complete_this_op (walk_state, op); | |
1057 | } | |
1058 | ||
1059 | acpi_ps_pop_scope (parser_state, &op, | |
1060 | &walk_state->arg_types, &walk_state->arg_count); | |
1061 | ||
1062 | } while (op); | |
1063 | ||
1064 | return_ACPI_STATUS (status); | |
1065 | } | |
1066 | ||
1067 | else if (ACPI_FAILURE (status)) { | |
1068 | acpi_ps_complete_this_op (walk_state, op); | |
1069 | return_ACPI_STATUS (status); | |
1070 | } | |
1071 | } | |
1072 | ||
1073 | acpi_ps_complete_this_op (walk_state, op); | |
1074 | } | |
1075 | ||
1076 | acpi_ps_pop_scope (parser_state, &op, &walk_state->arg_types, | |
1077 | &walk_state->arg_count); | |
1078 | ||
1079 | } while (op); | |
1080 | ||
1081 | return_ACPI_STATUS (status); | |
1082 | } | |
1083 | ||
1084 | ||
1085 | /******************************************************************************* | |
1086 | * | |
1087 | * FUNCTION: acpi_ps_parse_aml | |
1088 | * | |
44f6c012 | 1089 | * PARAMETERS: walk_state - Current state |
1da177e4 LT |
1090 | * |
1091 | * | |
1092 | * RETURN: Status | |
1093 | * | |
1094 | * DESCRIPTION: Parse raw AML and return a tree of ops | |
1095 | * | |
1096 | ******************************************************************************/ | |
1097 | ||
1098 | acpi_status | |
1099 | acpi_ps_parse_aml ( | |
1100 | struct acpi_walk_state *walk_state) | |
1101 | { | |
1102 | acpi_status status; | |
1103 | acpi_status terminate_status; | |
1104 | struct acpi_thread_state *thread; | |
1105 | struct acpi_thread_state *prev_walk_list = acpi_gbl_current_walk_list; | |
1106 | struct acpi_walk_state *previous_walk_state; | |
1107 | ||
1108 | ||
1109 | ACPI_FUNCTION_TRACE ("ps_parse_aml"); | |
1110 | ||
44f6c012 RM |
1111 | ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, |
1112 | "Entered with walk_state=%p Aml=%p size=%X\n", | |
1113 | walk_state, walk_state->parser_state.aml, | |
1114 | walk_state->parser_state.aml_size)); | |
1da177e4 LT |
1115 | |
1116 | ||
1117 | /* Create and initialize a new thread state */ | |
1118 | ||
1119 | thread = acpi_ut_create_thread_state (); | |
1120 | if (!thread) { | |
1121 | return_ACPI_STATUS (AE_NO_MEMORY); | |
1122 | } | |
1123 | ||
1124 | walk_state->thread = thread; | |
1125 | acpi_ds_push_walk_state (walk_state, thread); | |
1126 | ||
1127 | /* | |
1128 | * This global allows the AML debugger to get a handle to the currently | |
1129 | * executing control method. | |
1130 | */ | |
1131 | acpi_gbl_current_walk_list = thread; | |
1132 | ||
1133 | /* | |
1134 | * Execute the walk loop as long as there is a valid Walk State. This | |
1135 | * handles nested control method invocations without recursion. | |
1136 | */ | |
1137 | ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "State=%p\n", walk_state)); | |
1138 | ||
1139 | status = AE_OK; | |
1140 | while (walk_state) { | |
1141 | if (ACPI_SUCCESS (status)) { | |
1142 | /* | |
1143 | * The parse_loop executes AML until the method terminates | |
1144 | * or calls another method. | |
1145 | */ | |
1146 | status = acpi_ps_parse_loop (walk_state); | |
1147 | } | |
1148 | ||
1149 | ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, | |
1150 | "Completed one call to walk loop, %s State=%p\n", | |
1151 | acpi_format_exception (status), walk_state)); | |
1152 | ||
1153 | if (status == AE_CTRL_TRANSFER) { | |
1154 | /* | |
1155 | * A method call was detected. | |
1156 | * Transfer control to the called control method | |
1157 | */ | |
1158 | status = acpi_ds_call_control_method (thread, walk_state, NULL); | |
1159 | ||
1160 | /* | |
1161 | * If the transfer to the new method method call worked, a new walk | |
1162 | * state was created -- get it | |
1163 | */ | |
1164 | walk_state = acpi_ds_get_current_walk_state (thread); | |
1165 | continue; | |
1166 | } | |
1167 | else if (status == AE_CTRL_TERMINATE) { | |
1168 | status = AE_OK; | |
1169 | } | |
1170 | else if ((status != AE_OK) && (walk_state->method_desc)) { | |
1171 | ACPI_REPORT_METHOD_ERROR ("Method execution failed", | |
1172 | walk_state->method_node, NULL, status); | |
1173 | ||
1174 | /* Check for possible multi-thread reentrancy problem */ | |
1175 | ||
1176 | if ((status == AE_ALREADY_EXISTS) && | |
1177 | (!walk_state->method_desc->method.semaphore)) { | |
1178 | /* | |
44f6c012 RM |
1179 | * This method is marked not_serialized, but it tried to create |
1180 | * a named object, causing the second thread entrance to fail. | |
1181 | * We will workaround this by marking the method permanently | |
1182 | * as Serialized. | |
1da177e4 LT |
1183 | */ |
1184 | walk_state->method_desc->method.method_flags |= AML_METHOD_SERIALIZED; | |
1185 | walk_state->method_desc->method.concurrency = 1; | |
1186 | } | |
1187 | } | |
1188 | ||
1189 | if (walk_state->method_desc) { | |
1190 | /* Decrement the thread count on the method parse tree */ | |
1191 | ||
1192 | if (walk_state->method_desc->method.thread_count) { | |
1193 | walk_state->method_desc->method.thread_count--; | |
1194 | } | |
1195 | } | |
1196 | ||
1197 | /* We are done with this walk, move on to the parent if any */ | |
1198 | ||
1199 | walk_state = acpi_ds_pop_walk_state (thread); | |
1200 | ||
1201 | /* Reset the current scope to the beginning of scope stack */ | |
1202 | ||
1203 | acpi_ds_scope_stack_clear (walk_state); | |
1204 | ||
1205 | /* | |
1206 | * If we just returned from the execution of a control method, | |
1207 | * there's lots of cleanup to do | |
1208 | */ | |
1209 | if ((walk_state->parse_flags & ACPI_PARSE_MODE_MASK) == ACPI_PARSE_EXECUTE) { | |
1210 | terminate_status = acpi_ds_terminate_control_method (walk_state); | |
1211 | if (ACPI_FAILURE (terminate_status)) { | |
1212 | ACPI_REPORT_ERROR (( | |
1213 | "Could not terminate control method properly\n")); | |
1214 | ||
1215 | /* Ignore error and continue */ | |
1216 | } | |
1217 | } | |
1218 | ||
1219 | /* Delete this walk state and all linked control states */ | |
1220 | ||
1221 | acpi_ps_cleanup_scope (&walk_state->parser_state); | |
1222 | ||
1223 | previous_walk_state = walk_state; | |
1224 | ||
44f6c012 RM |
1225 | ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, |
1226 | "return_value=%p, implicit_value=%p State=%p\n", | |
1da177e4 LT |
1227 | walk_state->return_desc, walk_state->implicit_return_obj, walk_state)); |
1228 | ||
1229 | /* Check if we have restarted a preempted walk */ | |
1230 | ||
1231 | walk_state = acpi_ds_get_current_walk_state (thread); | |
1232 | if (walk_state) { | |
1233 | if (ACPI_SUCCESS (status)) { | |
1234 | /* | |
1235 | * There is another walk state, restart it. | |
1236 | * If the method return value is not used by the parent, | |
1237 | * The object is deleted | |
1238 | */ | |
1239 | if (!previous_walk_state->return_desc) { | |
1240 | status = acpi_ds_restart_control_method (walk_state, | |
1241 | previous_walk_state->implicit_return_obj); | |
1242 | } | |
1243 | else { | |
1244 | /* | |
1245 | * We have a valid return value, delete any implicit | |
1246 | * return value. | |
1247 | */ | |
1248 | acpi_ds_clear_implicit_return (previous_walk_state); | |
1249 | ||
1250 | status = acpi_ds_restart_control_method (walk_state, | |
1251 | previous_walk_state->return_desc); | |
1252 | } | |
1253 | if (ACPI_SUCCESS (status)) { | |
1254 | walk_state->walk_type |= ACPI_WALK_METHOD_RESTART; | |
1255 | } | |
1256 | } | |
1257 | else { | |
1258 | /* On error, delete any return object */ | |
1259 | ||
1260 | acpi_ut_remove_reference (previous_walk_state->return_desc); | |
1261 | } | |
1262 | } | |
1263 | ||
1264 | /* | |
1265 | * Just completed a 1st-level method, save the final internal return | |
1266 | * value (if any) | |
1267 | */ | |
1268 | else if (previous_walk_state->caller_return_desc) { | |
1269 | if (previous_walk_state->implicit_return_obj) { | |
44f6c012 RM |
1270 | *(previous_walk_state->caller_return_desc) = |
1271 | previous_walk_state->implicit_return_obj; | |
1da177e4 LT |
1272 | } |
1273 | else { | |
1274 | /* NULL if no return value */ | |
1275 | ||
44f6c012 RM |
1276 | *(previous_walk_state->caller_return_desc) = |
1277 | previous_walk_state->return_desc; | |
1da177e4 LT |
1278 | } |
1279 | } | |
1280 | else { | |
1281 | if (previous_walk_state->return_desc) { | |
1282 | /* Caller doesn't want it, must delete it */ | |
1283 | ||
1284 | acpi_ut_remove_reference (previous_walk_state->return_desc); | |
1285 | } | |
1286 | if (previous_walk_state->implicit_return_obj) { | |
1287 | /* Caller doesn't want it, must delete it */ | |
1288 | ||
1289 | acpi_ut_remove_reference (previous_walk_state->implicit_return_obj); | |
1290 | } | |
1291 | } | |
1292 | ||
1293 | acpi_ds_delete_walk_state (previous_walk_state); | |
1294 | } | |
1295 | ||
1296 | /* Normal exit */ | |
1297 | ||
1298 | acpi_ex_release_all_mutexes (thread); | |
1299 | acpi_ut_delete_generic_state (ACPI_CAST_PTR (union acpi_generic_state, thread)); | |
1300 | acpi_gbl_current_walk_list = prev_walk_list; | |
1301 | return_ACPI_STATUS (status); | |
1302 | } | |
1303 | ||
1304 |