OpenCores
URL https://opencores.org/ocsvn/test_project/test_project/trunk

Subversion Repositories test_project

[/] [test_project/] [trunk/] [linux_sd_driver/] [drivers/] [acpi/] [parser/] [psparse.c] - Blame information for rev 62

Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2025 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.