summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/acpi/dispatcher/dsopcode.c24
-rw-r--r--include/acpi/acconfig.h4
-rw-r--r--include/acpi/acexcep.h4
-rw-r--r--include/acpi/aclocal.h1
4 files changed, 29 insertions, 4 deletions
diff --git a/drivers/acpi/dispatcher/dsopcode.c b/drivers/acpi/dispatcher/dsopcode.c
index 5cd406676c2..50c892a49fa 100644
--- a/drivers/acpi/dispatcher/dsopcode.c
+++ b/drivers/acpi/dispatcher/dsopcode.c
@@ -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;
}
diff --git a/include/acpi/acconfig.h b/include/acpi/acconfig.h
index 29feee27f0e..e50fe715746 100644
--- a/include/acpi/acconfig.h
+++ b/include/acpi/acconfig.h
@@ -119,6 +119,10 @@
#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)
diff --git a/include/acpi/acexcep.h b/include/acpi/acexcep.h
index 84f5cb24286..a1ae1057d2e 100644
--- a/include/acpi/acexcep.h
+++ b/include/acpi/acexcep.h
@@ -153,8 +153,9 @@
#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[] = {
diff --git a/include/acpi/aclocal.h b/include/acpi/aclocal.h
index ecab527cf78..0323fa9aa3e 100644
--- a/include/acpi/aclocal.h
+++ b/include/acpi/aclocal.h
@@ -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 */
};
/*