Commit 026ad376 authored by Armin Wolf's avatar Armin Wolf Committed by Rafael J. Wysocki
Browse files

ACPICA: Abort AML bytecode execution when executing AML_FATAL_OP

The ACPI specification states that when executing AML_FATAL_OP,
the OS should log the fatal error event and shutdown in a timely
fashion.

Windows complies with this requirement by immediatly entering a
Bso_d, effectively aborting the execution of the AML bytecode in
question.

ACPICA however might continue with the AML bytecode execution
should acpi_os_signal() simply return AE_OK. This will cause issues
because ACPI BIOS implementations might assume that the Fatal()
operator does not return.

Fix this by aborting the AML bytecode execution in such a case
by returning AE_ERROR. Also turn struct acpi_signal_fatal_info into a
local variable because of its small size (12 bytes) and to ensure
that acpi_os_signal() always receives valid information about the
fatal ACPI BIOS error.

Link: https://github.com/acpica/acpica/commit/d516c7758ba6


Signed-off-by: default avatarArmin Wolf <W_Armin@gmx.de>
Signed-off-by: default avatarRafael J. Wysocki <rafael.j.wysocki@intel.com>
Link: https://patch.msgid.link/3325491.5fSG56mABF@rafael.j.wysocki
parent 30c2a333
Loading
Loading
Loading
Loading
+18 −28
Original line number Diff line number Diff line
@@ -10,6 +10,7 @@
#include <acpi/acpi.h>
#include "accommon.h"
#include "acinterp.h"
#include <acpi/acoutput.h>
#include "acparser.h"
#include "amlcode.h"

@@ -51,8 +52,7 @@ ACPI_MODULE_NAME("exoparg3")
acpi_status acpi_ex_opcode_3A_0T_0R(struct acpi_walk_state *walk_state)
{
	union acpi_operand_object **operand = &walk_state->operands[0];
	struct acpi_signal_fatal_info *fatal;
	acpi_status status = AE_OK;
	struct acpi_signal_fatal_info fatal;

	ACPI_FUNCTION_TRACE_STR(ex_opcode_3A_0T_0R,
				acpi_ps_get_opcode_name(walk_state->opcode));
@@ -60,28 +60,23 @@ acpi_status acpi_ex_opcode_3A_0T_0R(struct acpi_walk_state *walk_state)
	switch (walk_state->opcode) {
	case AML_FATAL_OP:	/* Fatal (fatal_type fatal_code fatal_arg) */

		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
				  "FatalOp: Type %X Code %X Arg %X "
				  "<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n",
				  (u32)operand[0]->integer.value,
				  (u32)operand[1]->integer.value,
				  (u32)operand[2]->integer.value));

		fatal = ACPI_ALLOCATE(sizeof(struct acpi_signal_fatal_info));
		if (fatal) {
			fatal->type = (u32) operand[0]->integer.value;
			fatal->code = (u32) operand[1]->integer.value;
			fatal->argument = (u32) operand[2]->integer.value;
		}
		fatal.type = (u32)operand[0]->integer.value;
		fatal.code = (u32)operand[1]->integer.value;
		fatal.argument = (u32)operand[2]->integer.value;

		/* Always signal the OS! */
		ACPI_BIOS_ERROR((AE_INFO,
				 "Fatal ACPI BIOS error (Type 0x%X Code 0x%X Arg 0x%X)\n",
				 fatal.type, fatal.code, fatal.argument));

		status = acpi_os_signal(ACPI_SIGNAL_FATAL, fatal);
		/* Always signal the OS! */

		/* Might return while OS is shutting down, just continue */
		acpi_os_signal(ACPI_SIGNAL_FATAL, &fatal);

		ACPI_FREE(fatal);
		goto cleanup;
		/*
		 * Might return while OS is shutting down, so abort the AML execution
		 * by returning an error.
		 */
		return_ACPI_STATUS(AE_ERROR);

	case AML_EXTERNAL_OP:
		/*
@@ -93,21 +88,16 @@ acpi_status acpi_ex_opcode_3A_0T_0R(struct acpi_walk_state *walk_state)
		 * wrong if an external opcode ever gets here.
		 */
		ACPI_ERROR((AE_INFO, "Executed External Op"));
		status = AE_OK;
		goto cleanup;

		return_ACPI_STATUS(AE_OK);

	default:

		ACPI_ERROR((AE_INFO, "Unknown AML opcode 0x%X",
			    walk_state->opcode));

		status = AE_AML_BAD_OPCODE;
		goto cleanup;
		return_ACPI_STATUS(AE_AML_BAD_OPCODE);
	}

cleanup:

	return_ACPI_STATUS(status);
}

/*******************************************************************************