diff options
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 |