Skip to content

Commit

Permalink
ACPICA: AML parser: attempt to continue loading table after error
Browse files Browse the repository at this point in the history
This change alters the parser so that the table load does not abort
upon an error.

Notable changes:

If there is an error while parsing an element of the termlist, we
will skip parsing the current termlist element and continue parsing
to the next opcode in the termlist.

If we get an error while parsing the conditional of If/Else/While or
the device name of Scope, we will skip the body of the statement all
together and pop the parser_state.

If we get an error while parsing the base offset and length of an
operation region declaration, we will remove the operation region
from the namespace.

Signed-off-by: Erik Schmauss <erik.schmauss@intel.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
  • Loading branch information
Erik Schmauss authored and Rafael J. Wysocki committed Jun 6, 2018
1 parent 3877b2c commit 5088814
Show file tree
Hide file tree
Showing 3 changed files with 85 additions and 6 deletions.
51 changes: 50 additions & 1 deletion drivers/acpi/acpica/psloop.c
Original file line number Diff line number Diff line change
Expand Up @@ -515,6 +515,22 @@ acpi_status acpi_ps_parse_loop(struct acpi_walk_state *walk_state)
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
if (walk_state->opcode == AML_SCOPE_OP) {
/*
* If the scope op fails to parse, skip the body of the
* scope op because the parse failure indicates that the
* device may not exist.
*/
walk_state->parser_state.aml =
walk_state->aml + 1;
walk_state->parser_state.aml =
acpi_ps_get_next_package_end
(&walk_state->parser_state);
walk_state->aml =
walk_state->parser_state.aml;
ACPI_ERROR((AE_INFO,
"Skipping Scope block"));
}

continue;
}
Expand Down Expand Up @@ -557,7 +573,40 @@ acpi_status acpi_ps_parse_loop(struct acpi_walk_state *walk_state)
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}

if ((walk_state->control_state) &&
((walk_state->control_state->control.
opcode == AML_IF_OP)
|| (walk_state->control_state->control.
opcode == AML_WHILE_OP))) {
/*
* If the if/while op fails to parse, we will skip parsing
* the body of the op.
*/
parser_state->aml =
walk_state->control_state->control.
aml_predicate_start + 1;
parser_state->aml =
acpi_ps_get_next_package_end
(parser_state);
walk_state->aml = parser_state->aml;

ACPI_ERROR((AE_INFO,
"Skipping While/If block"));
if (*walk_state->aml == AML_ELSE_OP) {
ACPI_ERROR((AE_INFO,
"Skipping Else block"));
walk_state->parser_state.aml =
walk_state->aml + 1;
walk_state->parser_state.aml =
acpi_ps_get_next_package_end
(parser_state);
walk_state->aml =
parser_state->aml;
}
ACPI_FREE(acpi_ut_pop_generic_state
(&walk_state->control_state));
}
op = NULL;
continue;
}
}
Expand Down
30 changes: 30 additions & 0 deletions drivers/acpi/acpica/psobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include "acparser.h"
#include "amlcode.h"
#include "acconvert.h"
#include "acnamesp.h"

#define _COMPONENT ACPI_PARSER
ACPI_MODULE_NAME("psobject")
Expand Down Expand Up @@ -549,6 +550,21 @@ acpi_ps_complete_op(struct acpi_walk_state *walk_state,

do {
if (*op) {
/*
* These Opcodes need to be removed from the namespace because they
* get created even if these opcodes cannot be created due to
* errors.
*/
if (((*op)->common.aml_opcode == AML_REGION_OP)
|| ((*op)->common.aml_opcode ==
AML_DATA_REGION_OP)) {
acpi_ns_delete_children((*op)->common.
node);
acpi_ns_remove_node((*op)->common.node);
(*op)->common.node = NULL;
acpi_ps_delete_parse_tree(*op);
}

status2 =
acpi_ps_complete_this_op(walk_state, *op);
if (ACPI_FAILURE(status2)) {
Expand All @@ -574,6 +590,20 @@ acpi_ps_complete_op(struct acpi_walk_state *walk_state,
#endif
walk_state->prev_op = NULL;
walk_state->prev_arg_types = walk_state->arg_types;

if (walk_state->parse_flags & ACPI_PARSE_MODULE_LEVEL) {
/*
* There was something that went wrong while executing code at the
* module-level. We need to skip parsing whatever caused the
* error and keep going. One runtime error during the table load
* should not cause the entire table to not be loaded. This is
* because there could be correct AML beyond the parts that caused
* the runtime error.
*/
ACPI_ERROR((AE_INFO,
"Ignore error and continue table load"));
return_ACPI_STATUS(AE_OK);
}
return_ACPI_STATUS(status);
}

Expand Down
10 changes: 5 additions & 5 deletions drivers/acpi/acpica/uterror.c
Original file line number Diff line number Diff line change
Expand Up @@ -182,20 +182,20 @@ acpi_ut_prefixed_namespace_error(const char *module_name,
switch (lookup_status) {
case AE_ALREADY_EXISTS:

acpi_os_printf(ACPI_MSG_BIOS_ERROR);
acpi_os_printf("\n" ACPI_MSG_BIOS_ERROR);
message = "Failure creating";
break;

case AE_NOT_FOUND:

acpi_os_printf(ACPI_MSG_BIOS_ERROR);
message = "Failure looking up";
acpi_os_printf("\n" ACPI_MSG_BIOS_ERROR);
message = "Could not resolve";
break;

default:

acpi_os_printf(ACPI_MSG_ERROR);
message = "Failure looking up";
acpi_os_printf("\n" ACPI_MSG_ERROR);
message = "Failure resolving";
break;
}

Expand Down

0 comments on commit 5088814

Please sign in to comment.