]> err.no Git - linux-2.6/blob - drivers/acpi/parser/psparse.c
Merge ../to-linus
[linux-2.6] / drivers / acpi / parser / psparse.c
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 /*******************************************************************************
66  *
67  * FUNCTION:    acpi_ps_get_opcode_size
68  *
69  * PARAMETERS:  Opcode          - An AML opcode
70  *
71  * RETURN:      Size of the opcode, in bytes (1 or 2)
72  *
73  * DESCRIPTION: Get the size of the current opcode.
74  *
75  ******************************************************************************/
76
77 u32
78 acpi_ps_get_opcode_size (
79         u32                             opcode)
80 {
81
82         /* Extended (2-byte) opcode if > 255 */
83
84         if (opcode > 0x00FF) {
85                 return (2);
86         }
87
88         /* Otherwise, just a single byte opcode */
89
90         return (1);
91 }
92
93
94 /*******************************************************************************
95  *
96  * FUNCTION:    acpi_ps_peek_opcode
97  *
98  * PARAMETERS:  parser_state        - A parser state object
99  *
100  * RETURN:      Next AML opcode
101  *
102  * DESCRIPTION: Get next AML opcode (without incrementing AML pointer)
103  *
104  ******************************************************************************/
105
106 u16
107 acpi_ps_peek_opcode (
108         struct acpi_parse_state         *parser_state)
109 {
110         u8                              *aml;
111         u16                             opcode;
112
113
114         aml = parser_state->aml;
115         opcode = (u16) ACPI_GET8 (aml);
116
117         if (opcode == AML_EXTENDED_OP_PREFIX) {
118                 /* Extended opcode, get the second opcode byte */
119
120                 aml++;
121                 opcode = (u16) ((opcode << 8) | ACPI_GET8 (aml));
122         }
123
124         return (opcode);
125 }
126
127
128 /*******************************************************************************
129  *
130  * FUNCTION:    acpi_ps_complete_this_op
131  *
132  * PARAMETERS:  walk_state      - Current State
133  *              Op              - Op to complete
134  *
135  * RETURN:      Status
136  *
137  * DESCRIPTION: Perform any cleanup at the completion of an Op.
138  *
139  ******************************************************************************/
140
141 acpi_status
142 acpi_ps_complete_this_op (
143         struct acpi_walk_state          *walk_state,
144         union acpi_parse_object         *op)
145 {
146         union acpi_parse_object         *prev;
147         union acpi_parse_object         *next;
148         const struct acpi_opcode_info   *parent_info;
149         union acpi_parse_object         *replacement_op = NULL;
150
151
152         ACPI_FUNCTION_TRACE_PTR ("ps_complete_this_op", op);
153
154
155         /* Check for null Op, can happen if AML code is corrupt */
156
157         if (!op) {
158                 return_ACPI_STATUS (AE_OK);  /* OK for now */
159         }
160
161         /* Delete this op and the subtree below it if asked to */
162
163         if (((walk_state->parse_flags & ACPI_PARSE_TREE_MASK) != ACPI_PARSE_DELETE_TREE) ||
164                  (walk_state->op_info->class == AML_CLASS_ARGUMENT)) {
165                 return_ACPI_STATUS (AE_OK);
166         }
167
168         /* Make sure that we only delete this subtree */
169
170         if (op->common.parent) {
171                 prev = op->common.parent->common.value.arg;
172                 if (!prev) {
173                         /* Nothing more to do */
174
175                         goto cleanup;
176                 }
177
178                 /*
179                  * Check if we need to replace the operator and its subtree
180                  * with a return value op (placeholder op)
181                  */
182                 parent_info = acpi_ps_get_opcode_info (op->common.parent->common.aml_opcode);
183
184                 switch (parent_info->class) {
185                 case AML_CLASS_CONTROL:
186                         break;
187
188                 case AML_CLASS_CREATE:
189
190                         /*
191                          * These opcodes contain term_arg operands. The current
192                          * op must be replaced by a placeholder return op
193                          */
194                         replacement_op = acpi_ps_alloc_op (AML_INT_RETURN_VALUE_OP);
195                         if (!replacement_op) {
196                                 goto allocate_error;
197                         }
198                         break;
199
200                 case AML_CLASS_NAMED_OBJECT:
201
202                         /*
203                          * These opcodes contain term_arg operands. The current
204                          * op must be replaced by a placeholder return op
205                          */
206                         if ((op->common.parent->common.aml_opcode == AML_REGION_OP)      ||
207                                 (op->common.parent->common.aml_opcode == AML_DATA_REGION_OP) ||
208                                 (op->common.parent->common.aml_opcode == AML_BUFFER_OP)      ||
209                                 (op->common.parent->common.aml_opcode == AML_PACKAGE_OP)     ||
210                                 (op->common.parent->common.aml_opcode == AML_VAR_PACKAGE_OP)) {
211                                 replacement_op = acpi_ps_alloc_op (AML_INT_RETURN_VALUE_OP);
212                                 if (!replacement_op) {
213                                         goto allocate_error;
214                                 }
215                         }
216                         else if ((op->common.parent->common.aml_opcode == AML_NAME_OP) &&
217                                          (walk_state->pass_number <= ACPI_IMODE_LOAD_PASS2)) {
218                                 if ((op->common.aml_opcode == AML_BUFFER_OP) ||
219                                         (op->common.aml_opcode == AML_PACKAGE_OP) ||
220                                         (op->common.aml_opcode == AML_VAR_PACKAGE_OP)) {
221                                         replacement_op = acpi_ps_alloc_op (op->common.aml_opcode);
222                                         if (!replacement_op) {
223                                                 goto allocate_error;
224                                         }
225
226                                         replacement_op->named.data = op->named.data;
227                                         replacement_op->named.length = op->named.length;
228                                 }
229                         }
230                         break;
231
232                 default:
233
234                         replacement_op = acpi_ps_alloc_op (AML_INT_RETURN_VALUE_OP);
235                         if (!replacement_op) {
236                                 goto allocate_error;
237                         }
238                 }
239
240                 /* We must unlink this op from the parent tree */
241
242                 if (prev == op) {
243                         /* This op is the first in the list */
244
245                         if (replacement_op) {
246                                 replacement_op->common.parent       = op->common.parent;
247                                 replacement_op->common.value.arg    = NULL;
248                                 replacement_op->common.node         = op->common.node;
249                                 op->common.parent->common.value.arg = replacement_op;
250                                 replacement_op->common.next         = op->common.next;
251                         }
252                         else {
253                                 op->common.parent->common.value.arg = op->common.next;
254                         }
255                 }
256
257                 /* Search the parent list */
258
259                 else while (prev) {
260                         /* Traverse all siblings in the parent's argument list */
261
262                         next = prev->common.next;
263                         if (next == op) {
264                                 if (replacement_op) {
265                                         replacement_op->common.parent   = op->common.parent;
266                                         replacement_op->common.value.arg = NULL;
267                                         replacement_op->common.node     = op->common.node;
268                                         prev->common.next               = replacement_op;
269                                         replacement_op->common.next     = op->common.next;
270                                         next = NULL;
271                                 }
272                                 else {
273                                         prev->common.next = op->common.next;
274                                         next = NULL;
275                                 }
276                         }
277                         prev = next;
278                 }
279         }
280
281
282 cleanup:
283
284         /* Now we can actually delete the subtree rooted at Op */
285
286         acpi_ps_delete_parse_tree (op);
287         return_ACPI_STATUS (AE_OK);
288
289
290 allocate_error:
291
292         /* Always delete the subtree, even on error */
293
294         acpi_ps_delete_parse_tree (op);
295         return_ACPI_STATUS (AE_NO_MEMORY);
296 }
297
298
299 /*******************************************************************************
300  *
301  * FUNCTION:    acpi_ps_next_parse_state
302  *
303  * PARAMETERS:  walk_state          - Current state
304  *              Op                  - Current parse op
305  *              callback_status     - Status from previous operation
306  *
307  * RETURN:      Status
308  *
309  * DESCRIPTION: Update the parser state based upon the return exception from
310  *              the parser callback.
311  *
312  ******************************************************************************/
313
314 acpi_status
315 acpi_ps_next_parse_state (
316         struct acpi_walk_state          *walk_state,
317         union acpi_parse_object         *op,
318         acpi_status                     callback_status)
319 {
320         struct acpi_parse_state         *parser_state = &walk_state->parser_state;
321         acpi_status                     status = AE_CTRL_PENDING;
322
323
324         ACPI_FUNCTION_TRACE_PTR ("ps_next_parse_state", op);
325
326
327         switch (callback_status) {
328         case AE_CTRL_TERMINATE:
329
330                 /*
331                  * A control method was terminated via a RETURN statement.
332                  * The walk of this method is complete.
333                  */
334                 parser_state->aml = parser_state->aml_end;
335                 status = AE_CTRL_TERMINATE;
336                 break;
337
338
339         case AE_CTRL_BREAK:
340
341                 parser_state->aml = walk_state->aml_last_while;
342                 walk_state->control_state->common.value = FALSE;
343                 status = AE_CTRL_BREAK;
344                 break;
345
346         case AE_CTRL_CONTINUE:
347
348
349                 parser_state->aml = walk_state->aml_last_while;
350                 status = AE_CTRL_CONTINUE;
351                 break;
352
353         case AE_CTRL_PENDING:
354
355                 parser_state->aml = walk_state->aml_last_while;
356                 break;
357
358 #if 0
359         case AE_CTRL_SKIP:
360
361                 parser_state->aml = parser_state->scope->parse_scope.pkg_end;
362                 status = AE_OK;
363                 break;
364 #endif
365
366         case AE_CTRL_TRUE:
367
368                 /*
369                  * Predicate of an IF was true, and we are at the matching ELSE.
370                  * Just close out this package
371                  */
372                 parser_state->aml = acpi_ps_get_next_package_end (parser_state);
373                 break;
374
375
376         case AE_CTRL_FALSE:
377
378                 /*
379                  * Either an IF/WHILE Predicate was false or we encountered a BREAK
380                  * opcode.  In both cases, we do not execute the rest of the
381                  * package;  We simply close out the parent (finishing the walk of
382                  * this branch of the tree) and continue execution at the parent
383                  * level.
384                  */
385                 parser_state->aml = parser_state->scope->parse_scope.pkg_end;
386
387                 /* In the case of a BREAK, just force a predicate (if any) to FALSE */
388
389                 walk_state->control_state->common.value = FALSE;
390                 status = AE_CTRL_END;
391                 break;
392
393
394         case AE_CTRL_TRANSFER:
395
396                 /* A method call (invocation) -- transfer control */
397
398                 status = AE_CTRL_TRANSFER;
399                 walk_state->prev_op = op;
400                 walk_state->method_call_op = op;
401                 walk_state->method_call_node = (op->common.value.arg)->common.node;
402
403                 /* Will return value (if any) be used by the caller? */
404
405                 walk_state->return_used = acpi_ds_is_result_used (op, walk_state);
406                 break;
407
408
409         default:
410
411                 status = callback_status;
412                 if ((callback_status & AE_CODE_MASK) == AE_CODE_CONTROL) {
413                         status = AE_OK;
414                 }
415                 break;
416         }
417
418         return_ACPI_STATUS (status);
419 }
420
421
422 /*******************************************************************************
423  *
424  * FUNCTION:    acpi_ps_parse_aml
425  *
426  * PARAMETERS:  walk_state      - Current state
427  *
428  *
429  * RETURN:      Status
430  *
431  * DESCRIPTION: Parse raw AML and return a tree of ops
432  *
433  ******************************************************************************/
434
435 acpi_status
436 acpi_ps_parse_aml (
437         struct acpi_walk_state          *walk_state)
438 {
439         acpi_status                     status;
440         acpi_status                     terminate_status;
441         struct acpi_thread_state        *thread;
442         struct acpi_thread_state        *prev_walk_list = acpi_gbl_current_walk_list;
443         struct acpi_walk_state          *previous_walk_state;
444
445
446         ACPI_FUNCTION_TRACE ("ps_parse_aml");
447
448         ACPI_DEBUG_PRINT ((ACPI_DB_PARSE,
449                 "Entered with walk_state=%p Aml=%p size=%X\n",
450                 walk_state, walk_state->parser_state.aml,
451                 walk_state->parser_state.aml_size));
452
453
454         /* Create and initialize a new thread state */
455
456         thread = acpi_ut_create_thread_state ();
457         if (!thread) {
458                 return_ACPI_STATUS (AE_NO_MEMORY);
459         }
460
461         walk_state->thread = thread;
462         acpi_ds_push_walk_state (walk_state, thread);
463
464         /*
465          * This global allows the AML debugger to get a handle to the currently
466          * executing control method.
467          */
468         acpi_gbl_current_walk_list = thread;
469
470         /*
471          * Execute the walk loop as long as there is a valid Walk State.  This
472          * handles nested control method invocations without recursion.
473          */
474         ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "State=%p\n", walk_state));
475
476         status = AE_OK;
477         while (walk_state) {
478                 if (ACPI_SUCCESS (status)) {
479                         /*
480                          * The parse_loop executes AML until the method terminates
481                          * or calls another method.
482                          */
483                         status = acpi_ps_parse_loop (walk_state);
484                 }
485
486                 ACPI_DEBUG_PRINT ((ACPI_DB_PARSE,
487                         "Completed one call to walk loop, %s State=%p\n",
488                         acpi_format_exception (status), walk_state));
489
490                 if (status == AE_CTRL_TRANSFER) {
491                         /*
492                          * A method call was detected.
493                          * Transfer control to the called control method
494                          */
495                         status = acpi_ds_call_control_method (thread, walk_state, NULL);
496
497                         /*
498                          * If the transfer to the new method method call worked, a new walk
499                          * state was created -- get it
500                          */
501                         walk_state = acpi_ds_get_current_walk_state (thread);
502                         continue;
503                 }
504                 else if (status == AE_CTRL_TERMINATE) {
505                         status = AE_OK;
506                 }
507                 else if ((status != AE_OK) && (walk_state->method_desc)) {
508                         ACPI_REPORT_METHOD_ERROR ("Method execution failed",
509                                 walk_state->method_node, NULL, status);
510
511                         /* Check for possible multi-thread reentrancy problem */
512
513                         if ((status == AE_ALREADY_EXISTS) &&
514                                 (!walk_state->method_desc->method.semaphore)) {
515                                 /*
516                                  * This method is marked not_serialized, but it tried to create
517                                  * a named object, causing the second thread entrance to fail.
518                                  * We will workaround this by marking the method permanently
519                                  * as Serialized.
520                                  */
521                                 walk_state->method_desc->method.method_flags |= AML_METHOD_SERIALIZED;
522                                 walk_state->method_desc->method.concurrency = 1;
523                         }
524                 }
525
526                 if (walk_state->method_desc) {
527                         /* Decrement the thread count on the method parse tree */
528
529                         if (walk_state->method_desc->method.thread_count) {
530                                 walk_state->method_desc->method.thread_count--;
531                         }
532                 }
533
534                 /* We are done with this walk, move on to the parent if any */
535
536                 walk_state = acpi_ds_pop_walk_state (thread);
537
538                 /* Reset the current scope to the beginning of scope stack */
539
540                 acpi_ds_scope_stack_clear (walk_state);
541
542                 /*
543                  * If we just returned from the execution of a control method,
544                  * there's lots of cleanup to do
545                  */
546                 if ((walk_state->parse_flags & ACPI_PARSE_MODE_MASK) == ACPI_PARSE_EXECUTE) {
547                         terminate_status = acpi_ds_terminate_control_method (walk_state);
548                         if (ACPI_FAILURE (terminate_status)) {
549                                 ACPI_REPORT_ERROR ((
550                                         "Could not terminate control method properly\n"));
551
552                                 /* Ignore error and continue */
553                         }
554                 }
555
556                 /* Delete this walk state and all linked control states */
557
558                 acpi_ps_cleanup_scope (&walk_state->parser_state);
559
560                 previous_walk_state = walk_state;
561
562                 ACPI_DEBUG_PRINT ((ACPI_DB_PARSE,
563                         "return_value=%p, implicit_value=%p State=%p\n",
564                         walk_state->return_desc, walk_state->implicit_return_obj, walk_state));
565
566                 /* Check if we have restarted a preempted walk */
567
568                 walk_state = acpi_ds_get_current_walk_state (thread);
569                 if (walk_state) {
570                         if (ACPI_SUCCESS (status)) {
571                                 /*
572                                  * There is another walk state, restart it.
573                                  * If the method return value is not used by the parent,
574                                  * The object is deleted
575                                  */
576                                 if (!previous_walk_state->return_desc) {
577                                         status = acpi_ds_restart_control_method (walk_state,
578                                                          previous_walk_state->implicit_return_obj);
579                                 }
580                                 else {
581                                         /*
582                                          * We have a valid return value, delete any implicit
583                                          * return value.
584                                          */
585                                         acpi_ds_clear_implicit_return (previous_walk_state);
586
587                                         status = acpi_ds_restart_control_method (walk_state,
588                                                          previous_walk_state->return_desc);
589                                 }
590                                 if (ACPI_SUCCESS (status)) {
591                                         walk_state->walk_type |= ACPI_WALK_METHOD_RESTART;
592                                 }
593                         }
594                         else {
595                                 /* On error, delete any return object */
596
597                                 acpi_ut_remove_reference (previous_walk_state->return_desc);
598                         }
599                 }
600
601                 /*
602                  * Just completed a 1st-level method, save the final internal return
603                  * value (if any)
604                  */
605                 else if (previous_walk_state->caller_return_desc) {
606                         if (previous_walk_state->implicit_return_obj) {
607                                 *(previous_walk_state->caller_return_desc) =
608                                         previous_walk_state->implicit_return_obj;
609                         }
610                         else {
611                                  /* NULL if no return value */
612
613                                 *(previous_walk_state->caller_return_desc) =
614                                         previous_walk_state->return_desc;
615                         }
616                 }
617                 else {
618                         if (previous_walk_state->return_desc) {
619                                 /* Caller doesn't want it, must delete it */
620
621                                 acpi_ut_remove_reference (previous_walk_state->return_desc);
622                         }
623                         if (previous_walk_state->implicit_return_obj) {
624                                 /* Caller doesn't want it, must delete it */
625
626                                 acpi_ut_remove_reference (previous_walk_state->implicit_return_obj);
627                         }
628                 }
629
630                 acpi_ds_delete_walk_state (previous_walk_state);
631         }
632
633         /* Normal exit */
634
635         acpi_ex_release_all_mutexes (thread);
636         acpi_ut_delete_generic_state (ACPI_CAST_PTR (union acpi_generic_state, thread));
637         acpi_gbl_current_walk_list = prev_walk_list;
638         return_ACPI_STATUS (status);
639 }
640
641