Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit fc374457 authored by Bob Moore's avatar Bob Moore Committed by Len Brown
Browse files

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: default avatarBob Moore <robert.moore@intel.com>
Signed-off-by: default avatarLin Ming <ming.m.lin@intel.com>
Signed-off-by: default avatarLen Brown <len.brown@intel.com>
parent 96411a63
Loading
Loading
Loading
Loading
+21 −3
Original line number Diff line number Diff line
@@ -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;
		}

+4 −0
Original line number Diff line number Diff line
@@ -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)
+3 −1
Original line number Diff line number Diff line
@@ -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[] = {
+1 −0
Original line number Diff line number Diff line
@@ -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 */
};

/*