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