ACPICA: Dispatcher: Introduce timeout mechanism for infinite loop detection
authorLv Zheng <lv.zheng@intel.com>
Fri, 17 Nov 2017 23:40:18 +0000 (15:40 -0800)
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>
Mon, 27 Nov 2017 00:20:29 +0000 (01:20 +0100)
ACPICA commit 9605023e7e6d1f05581502766c8cf2905bcc03d9

This patch implements a new infinite loop detection mechanism to replace
the old one, it uses acpi_os_get_timer() to limit loop execution into a
determined time slice.
This is useful in case some hardware/firmware operations really require the
AML interpreter to wait while the old mechanism could expire too fast on
recent machines.

The new mechanism converts old acpi_gbl_max_loop_iterations to store the user
configurable value for the new mechanism in order to allow users to be
still able to configure this value for acpiexec via command line. This
patch also removes wrong initilization code of acpi_gbl_max_loop_iterations
accordingly (it should have been initialized by ACPI_INIT_GLOBAL, and the
default value is also properly tuned for acpiexec). Reported by M. Foronda,
fixed by Lv Zheng.

Link: https://github.com/acpica/acpica/commit/9605023e
Link: https://bugzilla.kernel.org/show_bug.cgi?id=156501
Reported-by: M. Foronda <josemauricioforonda@gmail.com>
Signed-off-by: Lv Zheng <lv.zheng@intel.com>
Signed-off-by: Bob Moore <robert.moore@intel.com>
Signed-off-by: Erik Schmauss <erik.schmauss@intel.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
drivers/acpi/acpica/aclocal.h
drivers/acpi/acpica/dscontrol.c
drivers/acpi/acpica/utinit.c
include/acpi/acconfig.h
include/acpi/acpixf.h
include/acpi/actypes.h

index 0d45b8bb1678945eb296cdabce11f229cb349b65..bed041d41596b9613a6d36c4bf8860493ba5d80d 100644 (file)
@@ -622,7 +622,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 */
+       u64 loop_timeout;       /* While() loop timeout */
 };
 
 /*
index f470e81b0499789f63bba32b7e2ae617a169f646..244075dbc03aa1e1b8ff79d495ad95812dbc3d68 100644 (file)
@@ -118,6 +118,8 @@ acpi_ds_exec_begin_control_op(struct acpi_walk_state *walk_state,
                control_state->control.package_end =
                    walk_state->parser_state.pkg_end;
                control_state->control.opcode = op->common.aml_opcode;
+               control_state->control.loop_timeout = acpi_os_get_timer() +
+                   (u64)(acpi_gbl_max_loop_iterations * ACPI_100NSEC_PER_SEC);
 
                /* Push the control state on this walk's control stack */
 
@@ -206,14 +208,14 @@ acpi_ds_exec_end_control_op(struct acpi_walk_state *walk_state,
                        /* 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.
+                        * This infinite loop detection 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_gbl_max_loop_iterations) {
+                       if (ACPI_TIME_AFTER(acpi_os_get_timer(),
+                                           control_state->control.
+                                           loop_timeout)) {
                                status = AE_AML_INFINITE_LOOP;
                                break;
                        }
index 23e766d1691d25bef090dfed3d1db25c3a481281..45eeb0dcf283b78f2ba7cc45ec5dbaa6af579763 100644 (file)
@@ -206,7 +206,6 @@ acpi_status acpi_ut_init_globals(void)
        acpi_gbl_next_owner_id_offset = 0;
        acpi_gbl_debugger_configuration = DEBUGGER_THREADING;
        acpi_gbl_osi_mutex = NULL;
-       acpi_gbl_max_loop_iterations = ACPI_MAX_LOOP_COUNT;
 
        /* Hardware oriented */
 
index 6db3b4668b1a2b1e6c618d49565f96b1c4521021..ffe364fa4040c646c16edfaf3b2e827be62050ca 100644 (file)
 
 #define ACPI_ADDRESS_RANGE_MAX          2
 
-/* Maximum number of While() loops before abort */
+/* Maximum time (default 30s) of While() loops before abort */
 
-#define ACPI_MAX_LOOP_COUNT             0x000FFFFF
+#define ACPI_MAX_LOOP_TIMEOUT           30
 
 /******************************************************************************
  *
index e1dd1a8d42b60eb155796819b9518c34855cbfa5..1a4322db02749d864d421ecd69bd6154bcf3855e 100644 (file)
@@ -260,11 +260,11 @@ ACPI_INIT_GLOBAL(u8, acpi_gbl_osi_data, 0);
 ACPI_INIT_GLOBAL(u8, acpi_gbl_reduced_hardware, FALSE);
 
 /*
- * Maximum number of While() loop iterations before forced method abort.
+ * Maximum timeout for While() loop iterations before forced method abort.
  * This mechanism is intended to prevent infinite loops during interpreter
  * execution within a host kernel.
  */
-ACPI_INIT_GLOBAL(u32, acpi_gbl_max_loop_iterations, ACPI_MAX_LOOP_COUNT);
+ACPI_INIT_GLOBAL(u32, acpi_gbl_max_loop_iterations, ACPI_MAX_LOOP_TIMEOUT);
 
 /*
  * This mechanism is used to trace a specified AML method. The method is
index 4f077edb9b81b8086153609d6b4b22b4a22b96e0..ddde2790a54a1e86d5c87467cb80203ee163e83e 100644 (file)
@@ -468,6 +468,8 @@ typedef void *acpi_handle;  /* Actually a ptr to a NS Node */
 #define ACPI_NSEC_PER_MSEC              1000000L
 #define ACPI_NSEC_PER_SEC               1000000000L
 
+#define ACPI_TIME_AFTER(a, b)           ((s64)((b) - (a)) < 0)
+
 /* Owner IDs are used to track namespace nodes for selective deletion */
 
 typedef u8 acpi_owner_id;