aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi/acpica/psloop.c
diff options
context:
space:
mode:
authorLin Ming <ming.m.lin@intel.com>2009-08-13 02:03:15 -0400
committerLen Brown <len.brown@intel.com>2009-08-28 19:40:39 -0400
commit7f0c826a437157d2b19662977e9cf3b472cf24a6 (patch)
tree359c14eddb406007350e8f8a7bf96c9f8d85a2ab /drivers/acpi/acpica/psloop.c
parent999e08f99846a1fd6ee9642ec306a2d318925116 (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.c119
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
86acpi_ps_complete_final_op(struct acpi_walk_state *walk_state, 86acpi_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
89static void
90acpi_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
613static void
614acpi_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