ACPICA: Add a mechanism to escape infinite AML While() loops
authorBob Moore <robert.moore@intel.com>
Wed, 12 Nov 2008 07:15:29 +0000 (15:15 +0800)
committerLen Brown <len.brown@intel.com>
Tue, 30 Dec 2008 03:38:36 +0000 (22:38 -0500)
Add a loop counter to force exit from AML While loops if the
count becomes too large. This can occur in poorly written AML
when the hardware does not respond within a while loop and the
loop does not implement a timeout. The maximum loop count is
configurable. A new exception code is returned when a loop is
broken, AE_AML_INFINITE_LOOP.  Bob Moore, Alexey Starikovskiy.

Signed-off-by: Bob Moore <robert.moore@intel.com>
Signed-off-by: Lin Ming <ming.m.lin@intel.com>
Signed-off-by: Len Brown <len.brown@intel.com>
drivers/acpi/dispatcher/dsopcode.c
include/acpi/acconfig.h
include/acpi/acexcep.h
include/acpi/aclocal.h

index 5cd406676c2ccdfa126806c936e34d600204bf8e..50c892a49fa35a44db5742e098e45ad31bc34b38 100644 (file)
@@ -1262,13 +1262,31 @@ acpi_ds_exec_end_control_op(struct acpi_walk_state * walk_state,
 
                ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, "[WHILE_OP] Op=%p\n", op));
 
-               if (walk_state->control_state->common.value) {
+               control_state = walk_state->control_state;
+               if (control_state->common.value) {
 
-                       /* Predicate was true, go back and evaluate it again! */
+                       /* Predicate was true, the body of the loop was just executed */
 
+                       /*
+                        * This loop counter mechanism allows the interpreter to escape
+                        * possibly infinite loops. This can occur in poorly written AML
+                        * when the hardware does not respond within a while loop and the
+                        * loop does not implement a timeout.
+                        */
+                       control_state->control.loop_count++;
+                       if (control_state->control.loop_count >
+                               ACPI_MAX_LOOP_ITERATIONS) {
+                               status = AE_AML_INFINITE_LOOP;
+                               break;
+                       }
+
+                       /*
+                        * Go back and evaluate the predicate and maybe execute the loop
+                        * another time
+                        */
                        status = AE_CTRL_PENDING;
                        walk_state->aml_last_while =
-                           walk_state->control_state->control.aml_predicate_start;
+                           control_state->control.aml_predicate_start;
                        break;
                }
 
index 29feee27f0ea8aeef29352635eb4f6720f55e1f2..e50fe7157463b855045e1ae959a065efd1fb3155 100644 (file)
 
 #define ACPI_ROOT_TABLE_SIZE_INCREMENT  4
 
+/* Maximum number of While() loop iterations before forced abort */
+
+#define ACPI_MAX_LOOP_ITERATIONS        0xFFFF
+
 /******************************************************************************
  *
  * ACPI Specification constants (Do not change unless the specification changes)
index 84f5cb242863c28829c3919b62c57c1e699c68e3..a1ae1057d2ef6fe0cd43d00613459c7d04aebb05 100644 (file)
 #define AE_AML_CIRCULAR_REFERENCE       (acpi_status) (0x001E | AE_CODE_AML)
 #define AE_AML_BAD_RESOURCE_LENGTH      (acpi_status) (0x001F | AE_CODE_AML)
 #define AE_AML_ILLEGAL_ADDRESS          (acpi_status) (0x0020 | AE_CODE_AML)
+#define AE_AML_INFINITE_LOOP            (acpi_status) (0x0021 | AE_CODE_AML)
 
-#define AE_CODE_AML_MAX                 0x0020
+#define AE_CODE_AML_MAX                 0x0021
 
 /*
  * Internal exceptions used for control
@@ -267,6 +268,7 @@ char const *acpi_gbl_exception_names_aml[] = {
        "AE_AML_CIRCULAR_REFERENCE",
        "AE_AML_BAD_RESOURCE_LENGTH",
        "AE_AML_ILLEGAL_ADDRESS",
+       "AE_AML_INFINITE_LOOP"
 };
 
 char const *acpi_gbl_exception_names_ctrl[] = {
index ecab527cf78ef72afe33309782bf184a12c13641..0323fa9aa3e6ae779a4fd7f424f143bf839e0893 100644 (file)
@@ -566,6 +566,7 @@ struct acpi_control_state {
        union acpi_parse_object *predicate_op;
        u8 *aml_predicate_start;        /* Start of if/while predicate */
        u8 *package_end;        /* End of if/while block */
+       u32 loop_count;         /* While() loop counter */
 };
 
 /*