diff options
author | Lin Ming <ming.m.lin@intel.com> | 2009-08-13 02:03:15 -0400 |
---|---|---|
committer | Len Brown <len.brown@intel.com> | 2009-08-28 19:40:39 -0400 |
commit | 7f0c826a437157d2b19662977e9cf3b472cf24a6 (patch) | |
tree | 359c14eddb406007350e8f8a7bf96c9f8d85a2ab /drivers/acpi/acpica/psloop.c | |
parent | 999e08f99846a1fd6ee9642ec306a2d318925116 (diff) |
ACPICA: Add support for module-level executable AML code
Add limited support for executable AML code that exists outside
of any control method. This type of code has been illegal since
ACPI 2.0. The code must exist in an If/Else/While block. All AML
tables are supported, including tables that are dynamically loaded.
ACPICA BZ 762.
http://acpica.org/bugzilla/show_bug.cgi?id=762
Signed-off-by: Lin Ming <ming.m.lin@intel.com>
Signed-off-by: Bob Moore <robert.moore@intel.com>
Signed-off-by: Len Brown <len.brown@intel.com>
Diffstat (limited to 'drivers/acpi/acpica/psloop.c')
-rw-r--r-- | drivers/acpi/acpica/psloop.c | 119 |
1 files changed, 111 insertions, 8 deletions
diff --git a/drivers/acpi/acpica/psloop.c b/drivers/acpi/acpica/psloop.c index c5f6ce19a401..cd7995b3aed4 100644 --- a/drivers/acpi/acpica/psloop.c +++ b/drivers/acpi/acpica/psloop.c | |||
@@ -86,6 +86,9 @@ static acpi_status | |||
86 | acpi_ps_complete_final_op(struct acpi_walk_state *walk_state, | 86 | acpi_ps_complete_final_op(struct acpi_walk_state *walk_state, |
87 | union acpi_parse_object *op, acpi_status status); | 87 | union acpi_parse_object *op, acpi_status status); |
88 | 88 | ||
89 | static void | ||
90 | acpi_ps_link_module_code(u8 *aml_start, u32 aml_length, acpi_owner_id owner_id); | ||
91 | |||
89 | /******************************************************************************* | 92 | /******************************************************************************* |
90 | * | 93 | * |
91 | * FUNCTION: acpi_ps_get_aml_opcode | 94 | * FUNCTION: acpi_ps_get_aml_opcode |
@@ -390,6 +393,7 @@ acpi_ps_get_arguments(struct acpi_walk_state *walk_state, | |||
390 | { | 393 | { |
391 | acpi_status status = AE_OK; | 394 | acpi_status status = AE_OK; |
392 | union acpi_parse_object *arg = NULL; | 395 | union acpi_parse_object *arg = NULL; |
396 | const struct acpi_opcode_info *op_info; | ||
393 | 397 | ||
394 | ACPI_FUNCTION_TRACE_PTR(ps_get_arguments, walk_state); | 398 | ACPI_FUNCTION_TRACE_PTR(ps_get_arguments, walk_state); |
395 | 399 | ||
@@ -449,13 +453,11 @@ acpi_ps_get_arguments(struct acpi_walk_state *walk_state, | |||
449 | INCREMENT_ARG_LIST(walk_state->arg_types); | 453 | INCREMENT_ARG_LIST(walk_state->arg_types); |
450 | } | 454 | } |
451 | 455 | ||
452 | /* Special processing for certain opcodes */ | 456 | /* |
453 | 457 | * Handle executable code at "module-level". This refers to | |
454 | /* TBD (remove): Temporary mechanism to disable this code if needed */ | 458 | * executable opcodes that appear outside of any control method. |
455 | 459 | */ | |
456 | #ifdef ACPI_ENABLE_MODULE_LEVEL_CODE | 460 | if ((walk_state->pass_number <= ACPI_IMODE_LOAD_PASS2) && |
457 | |||
458 | if ((walk_state->pass_number <= ACPI_IMODE_LOAD_PASS1) && | ||
459 | ((walk_state->parse_flags & ACPI_PARSE_DISASSEMBLE) == 0)) { | 461 | ((walk_state->parse_flags & ACPI_PARSE_DISASSEMBLE) == 0)) { |
460 | /* | 462 | /* |
461 | * We want to skip If/Else/While constructs during Pass1 because we | 463 | * We want to skip If/Else/While constructs during Pass1 because we |
@@ -469,6 +471,23 @@ acpi_ps_get_arguments(struct acpi_walk_state *walk_state, | |||
469 | case AML_ELSE_OP: | 471 | case AML_ELSE_OP: |
470 | case AML_WHILE_OP: | 472 | case AML_WHILE_OP: |
471 | 473 | ||
474 | /* | ||
475 | * Currently supported module-level opcodes are: | ||
476 | * IF/ELSE/WHILE. These appear to be the most common, | ||
477 | * and easiest to support since they open an AML | ||
478 | * package. | ||
479 | */ | ||
480 | if (walk_state->pass_number == | ||
481 | ACPI_IMODE_LOAD_PASS1) { | ||
482 | acpi_ps_link_module_code(aml_op_start, | ||
483 | walk_state-> | ||
484 | parser_state. | ||
485 | pkg_end - | ||
486 | aml_op_start, | ||
487 | walk_state-> | ||
488 | owner_id); | ||
489 | } | ||
490 | |||
472 | ACPI_DEBUG_PRINT((ACPI_DB_PARSE, | 491 | ACPI_DEBUG_PRINT((ACPI_DB_PARSE, |
473 | "Pass1: Skipping an If/Else/While body\n")); | 492 | "Pass1: Skipping an If/Else/While body\n")); |
474 | 493 | ||
@@ -480,10 +499,34 @@ acpi_ps_get_arguments(struct acpi_walk_state *walk_state, | |||
480 | break; | 499 | break; |
481 | 500 | ||
482 | default: | 501 | default: |
502 | /* | ||
503 | * Check for an unsupported executable opcode at module | ||
504 | * level. We must be in PASS1, the parent must be a SCOPE, | ||
505 | * The opcode class must be EXECUTE, and the opcode must | ||
506 | * not be an argument to another opcode. | ||
507 | */ | ||
508 | if ((walk_state->pass_number == | ||
509 | ACPI_IMODE_LOAD_PASS1) | ||
510 | && (op->common.parent->common.aml_opcode == | ||
511 | AML_SCOPE_OP)) { | ||
512 | op_info = | ||
513 | acpi_ps_get_opcode_info(op->common. | ||
514 | aml_opcode); | ||
515 | if ((op_info->class == | ||
516 | AML_CLASS_EXECUTE) && (!arg)) { | ||
517 | ACPI_WARNING((AE_INFO, | ||
518 | "Detected an unsupported executable opcode " | ||
519 | "at module-level: [0x%.4X] at table offset 0x%.4X", | ||
520 | op->common.aml_opcode, | ||
521 | (u32)((aml_op_start - walk_state->parser_state.aml_start) | ||
522 | + sizeof(struct acpi_table_header)))); | ||
523 | } | ||
524 | } | ||
483 | break; | 525 | break; |
484 | } | 526 | } |
485 | } | 527 | } |
486 | #endif | 528 | |
529 | /* Special processing for certain opcodes */ | ||
487 | 530 | ||
488 | switch (op->common.aml_opcode) { | 531 | switch (op->common.aml_opcode) { |
489 | case AML_METHOD_OP: | 532 | case AML_METHOD_OP: |
@@ -553,6 +596,66 @@ acpi_ps_get_arguments(struct acpi_walk_state *walk_state, | |||
553 | 596 | ||
554 | /******************************************************************************* | 597 | /******************************************************************************* |
555 | * | 598 | * |
599 | * FUNCTION: acpi_ps_link_module_code | ||
600 | * | ||
601 | * PARAMETERS: aml_start - Pointer to the AML | ||
602 | * aml_length - Length of executable AML | ||
603 | * owner_id - owner_id of module level code | ||
604 | * | ||
605 | * RETURN: None. | ||
606 | * | ||
607 | * DESCRIPTION: Wrap the module-level code with a method object and link the | ||
608 | * object to the global list. Note, the mutex field of the method | ||
609 | * object is used to link multiple module-level code objects. | ||
610 | * | ||
611 | ******************************************************************************/ | ||
612 | |||
613 | static void | ||
614 | acpi_ps_link_module_code(u8 *aml_start, u32 aml_length, acpi_owner_id owner_id) | ||
615 | { | ||
616 | union acpi_operand_object *prev; | ||
617 | union acpi_operand_object *next; | ||
618 | union acpi_operand_object *method_obj; | ||
619 | |||
620 | /* Get the tail of the list */ | ||
621 | |||
622 | prev = next = acpi_gbl_module_code_list; | ||
623 | while (next) { | ||
624 | prev = next; | ||
625 | next = next->method.mutex; | ||
626 | } | ||
627 | |||
628 | /* | ||
629 | * Insert the module level code into the list. Merge it if it is | ||
630 | * adjacent to the previous element. | ||
631 | */ | ||
632 | if (!prev || | ||
633 | ((prev->method.aml_start + prev->method.aml_length) != aml_start)) { | ||
634 | |||
635 | /* Create, initialize, and link a new temporary method object */ | ||
636 | |||
637 | method_obj = acpi_ut_create_internal_object(ACPI_TYPE_METHOD); | ||
638 | if (!method_obj) { | ||
639 | return; | ||
640 | } | ||
641 | |||
642 | method_obj->method.aml_start = aml_start; | ||
643 | method_obj->method.aml_length = aml_length; | ||
644 | method_obj->method.owner_id = owner_id; | ||
645 | method_obj->method.flags |= AOPOBJ_MODULE_LEVEL; | ||
646 | |||
647 | if (!prev) { | ||
648 | acpi_gbl_module_code_list = method_obj; | ||
649 | } else { | ||
650 | prev->method.mutex = method_obj; | ||
651 | } | ||
652 | } else { | ||
653 | prev->method.aml_length += aml_length; | ||
654 | } | ||
655 | } | ||
656 | |||
657 | /******************************************************************************* | ||
658 | * | ||
556 | * FUNCTION: acpi_ps_complete_op | 659 | * FUNCTION: acpi_ps_complete_op |
557 | * | 660 | * |
558 | * PARAMETERS: walk_state - Current state | 661 | * PARAMETERS: walk_state - Current state |