diff options
author | Bob Moore <robert.moore@intel.com> | 2008-11-12 02:15:29 -0500 |
---|---|---|
committer | Len Brown <len.brown@intel.com> | 2008-12-29 22:38:36 -0500 |
commit | fc37445733aeae4fd1a20385850620354263b1d5 (patch) | |
tree | a989d6bf8dcc2011f25e365532c3855a48f11c62 | |
parent | 96411a630412f057d365aa1e9de7d23c069d627a (diff) |
ACPICA: Add a mechanism to escape infinite AML While() loops
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>
-rw-r--r-- | drivers/acpi/dispatcher/dsopcode.c | 24 | ||||
-rw-r--r-- | include/acpi/acconfig.h | 4 | ||||
-rw-r--r-- | include/acpi/acexcep.h | 4 | ||||
-rw-r--r-- | include/acpi/aclocal.h | 1 |
4 files changed, 29 insertions, 4 deletions
diff --git a/drivers/acpi/dispatcher/dsopcode.c b/drivers/acpi/dispatcher/dsopcode.c index 5cd406676c2c..50c892a49fa3 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, | |||
1262 | 1262 | ||
1263 | ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, "[WHILE_OP] Op=%p\n", op)); | 1263 | ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, "[WHILE_OP] Op=%p\n", op)); |
1264 | 1264 | ||
1265 | if (walk_state->control_state->common.value) { | 1265 | control_state = walk_state->control_state; |
1266 | if (control_state->common.value) { | ||
1266 | 1267 | ||
1267 | /* Predicate was true, go back and evaluate it again! */ | 1268 | /* Predicate was true, the body of the loop was just executed */ |
1268 | 1269 | ||
1270 | /* | ||
1271 | * This loop counter mechanism allows the interpreter to escape | ||
1272 | * possibly infinite loops. This can occur in poorly written AML | ||
1273 | * when the hardware does not respond within a while loop and the | ||
1274 | * loop does not implement a timeout. | ||
1275 | */ | ||
1276 | control_state->control.loop_count++; | ||
1277 | if (control_state->control.loop_count > | ||
1278 | ACPI_MAX_LOOP_ITERATIONS) { | ||
1279 | status = AE_AML_INFINITE_LOOP; | ||
1280 | break; | ||
1281 | } | ||
1282 | |||
1283 | /* | ||
1284 | * Go back and evaluate the predicate and maybe execute the loop | ||
1285 | * another time | ||
1286 | */ | ||
1269 | status = AE_CTRL_PENDING; | 1287 | status = AE_CTRL_PENDING; |
1270 | walk_state->aml_last_while = | 1288 | walk_state->aml_last_while = |
1271 | walk_state->control_state->control.aml_predicate_start; | 1289 | control_state->control.aml_predicate_start; |
1272 | break; | 1290 | break; |
1273 | } | 1291 | } |
1274 | 1292 | ||
diff --git a/include/acpi/acconfig.h b/include/acpi/acconfig.h index 29feee27f0ea..e50fe7157463 100644 --- a/include/acpi/acconfig.h +++ b/include/acpi/acconfig.h | |||
@@ -119,6 +119,10 @@ | |||
119 | 119 | ||
120 | #define ACPI_ROOT_TABLE_SIZE_INCREMENT 4 | 120 | #define ACPI_ROOT_TABLE_SIZE_INCREMENT 4 |
121 | 121 | ||
122 | /* Maximum number of While() loop iterations before forced abort */ | ||
123 | |||
124 | #define ACPI_MAX_LOOP_ITERATIONS 0xFFFF | ||
125 | |||
122 | /****************************************************************************** | 126 | /****************************************************************************** |
123 | * | 127 | * |
124 | * ACPI Specification constants (Do not change unless the specification changes) | 128 | * ACPI Specification constants (Do not change unless the specification changes) |
diff --git a/include/acpi/acexcep.h b/include/acpi/acexcep.h index 84f5cb242863..a1ae1057d2ef 100644 --- a/include/acpi/acexcep.h +++ b/include/acpi/acexcep.h | |||
@@ -153,8 +153,9 @@ | |||
153 | #define AE_AML_CIRCULAR_REFERENCE (acpi_status) (0x001E | AE_CODE_AML) | 153 | #define AE_AML_CIRCULAR_REFERENCE (acpi_status) (0x001E | AE_CODE_AML) |
154 | #define AE_AML_BAD_RESOURCE_LENGTH (acpi_status) (0x001F | AE_CODE_AML) | 154 | #define AE_AML_BAD_RESOURCE_LENGTH (acpi_status) (0x001F | AE_CODE_AML) |
155 | #define AE_AML_ILLEGAL_ADDRESS (acpi_status) (0x0020 | AE_CODE_AML) | 155 | #define AE_AML_ILLEGAL_ADDRESS (acpi_status) (0x0020 | AE_CODE_AML) |
156 | #define AE_AML_INFINITE_LOOP (acpi_status) (0x0021 | AE_CODE_AML) | ||
156 | 157 | ||
157 | #define AE_CODE_AML_MAX 0x0020 | 158 | #define AE_CODE_AML_MAX 0x0021 |
158 | 159 | ||
159 | /* | 160 | /* |
160 | * Internal exceptions used for control | 161 | * Internal exceptions used for control |
@@ -267,6 +268,7 @@ char const *acpi_gbl_exception_names_aml[] = { | |||
267 | "AE_AML_CIRCULAR_REFERENCE", | 268 | "AE_AML_CIRCULAR_REFERENCE", |
268 | "AE_AML_BAD_RESOURCE_LENGTH", | 269 | "AE_AML_BAD_RESOURCE_LENGTH", |
269 | "AE_AML_ILLEGAL_ADDRESS", | 270 | "AE_AML_ILLEGAL_ADDRESS", |
271 | "AE_AML_INFINITE_LOOP" | ||
270 | }; | 272 | }; |
271 | 273 | ||
272 | char const *acpi_gbl_exception_names_ctrl[] = { | 274 | char const *acpi_gbl_exception_names_ctrl[] = { |
diff --git a/include/acpi/aclocal.h b/include/acpi/aclocal.h index ecab527cf78e..0323fa9aa3e6 100644 --- a/include/acpi/aclocal.h +++ b/include/acpi/aclocal.h | |||
@@ -566,6 +566,7 @@ struct acpi_control_state { | |||
566 | union acpi_parse_object *predicate_op; | 566 | union acpi_parse_object *predicate_op; |
567 | u8 *aml_predicate_start; /* Start of if/while predicate */ | 567 | u8 *aml_predicate_start; /* Start of if/while predicate */ |
568 | u8 *package_end; /* End of if/while block */ | 568 | u8 *package_end; /* End of if/while block */ |
569 | u32 loop_count; /* While() loop counter */ | ||
569 | }; | 570 | }; |
570 | 571 | ||
571 | /* | 572 | /* |